//===-- NaClObjDump.cpp - Dump PNaCl bitcode contents ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/NaCl/PNaClABIProps.h"
#include "llvm/Analysis/NaCl/PNaClABITypeChecker.h"
#include "llvm/Analysis/NaCl/PNaClAllowedIntrinsics.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
#include "llvm/Bitcode/NaCl/NaClBitCodes.h"
#include "llvm/Bitcode/NaCl/NaClObjDumpStream.h"
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"

#include <map>

namespace {

using namespace llvm;

static cl::opt<bool>
ReportWarningsAsErrors(
    "Werror",
    cl::desc("Report warnings as errors."),
    cl::init(false));

static cl::opt<bool>
IgnorePNaClABIChecks(
    "ignore-pnaclabi-checks",
    cl::desc("Ignore checking bitcode for PNaCl ABI violations"),
    cl::init(false));

/// Class to handle sign rotations in a human readable form. That is,
/// the sign is in the low bit. The two special cases are:
/// 1) -1 is true for i1.
/// 2) The representation allows -0 (which is different than 0).
class SignRotatedInt {
public:
  SignRotatedInt(uint64_t Value, Type* ValueType)
      : SignedValue(Value >> 1),
        IsNegated((Value & 0x1)
                  && !(ValueType->isIntegerTy()
                       && ValueType->getIntegerBitWidth() == 1)) {
  }

  SignRotatedInt()
      : SignedValue(0), IsNegated(false) {}

  explicit SignRotatedInt(const SignRotatedInt &V)
      : SignedValue(V.SignedValue), IsNegated(V.IsNegated) {}

  void operator=(const SignRotatedInt &V) {
    SignedValue = V.SignedValue;
    IsNegated = V.IsNegated;
  }

  void Print(raw_ostream &Strm) const {
    if (IsNegated) Strm << "-";
    Strm << SignedValue;
  }

private:
  int64_t SignedValue;
  bool IsNegated;
};

inline raw_ostream &operator<<(raw_ostream &Strm, const SignRotatedInt &V) {
  V.Print(Strm);
  return Strm;
}

/// Convenience class to be able to print value ids to raw_ostream's.
/// Kinds of bitcode Ids:
///    a : For abbreviations.
///    b : For basic blocks.
///    c : For local constants.
///    f : For function addresses.
///    g : For global variable addresses.
///    p : For parameter arguments.
///    t : For type values.
///    v : For values generated by instructions.
class BitcodeId {
public:
  BitcodeId(char Kind, uint32_t Index)
      : Kind(Kind), Index(Index), IsGlobal(IsGlobalKind(Kind)) {
  }

  BitcodeId(const BitcodeId &Id)
      : Kind(Id.Kind), Index(Id.Index), IsGlobal(Id.IsGlobal) {}

  BitcodeId(char Kind, uint32_t Index, bool IsGlobal)
      : Kind(Kind), Index(Index), IsGlobal(IsGlobal) {}

  void operator=(const BitcodeId &Id) {
    Kind = Id.Kind;
    Index = Id.Index;
    IsGlobal = Id.IsGlobal;
  }

  raw_ostream &Print(raw_ostream &Stream) const {
    return Stream << Prefix() << Kind << Index;
  }

  char GetKind() const {
    return Kind;
  }

  std::string GetName() const {
    std::string Buffer;
    raw_string_ostream StrBuf(Buffer);
    Print(StrBuf);
    return StrBuf.str();
  }

private:
  char Kind;
  uint32_t Index;
  bool IsGlobal;

  // Returns true if (default) assumption for kind implies global.
  static bool IsGlobalKind(char Kind);

  // Returns the bitcode prefix character that communicates if the
  // bitcode Id is lcoal or global.
  char Prefix() const { return IsGlobal ? '@' : '%'; }
};

bool BitcodeId::IsGlobalKind(char Kind) {
  switch (Kind) {
  case 'f':
  case 'g':
  case 't':
    return true;
  case 'b':
  case 'c':
  case 'p':
  case 'v':
    return false;
  default:
    errs() << "Bad bitcode id, can't determine (statically) if global: "
           << Kind << "\n";
    report_fatal_error("Unable to continue");
  }
}

raw_ostream &operator<<(raw_ostream &Stream, const BitcodeId &Id) {
  return Id.Print(Stream);
}

class NaClDisBlockParser;

/// The text formatter for PNaClAsm instructions.
class AssemblyTextFormatter : public naclbitc::TextFormatter {
public:
  // Special directive to tokenize type expressions. Used to convert
  // type signatures into a sequence of tokens.
  class TypeDirective : public naclbitc::TextFormatter::Directive {
  public:
    TypeDirective(TextFormatter *Formatter)
        : naclbitc::TextFormatter::Directive(Formatter),
          Typ(0),
          FcnId(0),
          AddParams(false) {}

    ~TypeDirective() override {}

  private:
    /// Calls the corresponding method in AssemblyTextFormatter, with
    /// the locally stored arguments.
    void MyApply(bool Replay) const override;

    void MaybeSaveForReplay() const override {}

    // The type to tokenize.
    Type *Typ;
    // Pointer to function id, if not NULL.
    BitcodeId *FcnId;
    // true if parameter id's should be added to function signature.
    bool AddParams;

    friend class AssemblyTextFormatter;

    // Internal routine to allow AssemblyTextFormatter::AllocateTypeDirective
    // to initialize a type directive.
    void Init(Type *NewTyp, BitcodeId *NewFcnId, bool NewAddParams) {
      Typ = NewTyp;
      FcnId = NewFcnId;
      AddParams = NewAddParams;
    }
  };

  // Special directive to tokenize an abbreviation. Used to convert
  // an abbreviation (pointer) into a sequence of tokens.
  class AbbreviationDirective : public naclbitc::TextFormatter::Directive {
  public:
    AbbreviationDirective(TextFormatter *Formatter)
        : naclbitc::TextFormatter::Directive(Formatter),
          Abbrev(0) {}

    ~AbbreviationDirective() override {}

  private:
    void MyApply(bool Replay) const override;

    void MaybeSaveForReplay() const override {}

    // The abbreviation to tokenize.
    NaClBitCodeAbbrev *Abbrev;

    friend class AssemblyTextFormatter;
  };

  // Special directive to tokenize an abbreviation index, if the corresponding
  // record in the block parser used a user-defined abbreviation.
  class AbbrevIndexDirective : public naclbitc::TextFormatter::Directive {
  public:
    AbbrevIndexDirective(TextFormatter *Formatter)
        : naclbitc::TextFormatter::Directive(Formatter),
          Record(0), NumGlobalAbbreviations(0) {}

    ~AbbrevIndexDirective() override {}

  private:
    void MyApply(bool Replay) const override;

    void MaybeSaveForReplay() const override {}

    // The record containing the associated abbreviation.
    NaClBitcodeRecord *Record;

    // The number of global abbreviations defined for the block the
    // record appears in.
    unsigned NumGlobalAbbreviations;

    friend class AssemblyTextFormatter;
  };

public:

  /// Creates an assembly text formatter for the given dump stream.
  AssemblyTextFormatter(naclbitc::ObjDumpStream &ObjDump)
      : TextFormatter(ObjDump.Assembly(),
                      std::max(20U, GetAssemblyWidth(ObjDump)),
                      "  "),
        Comma(this, ","),
        Semicolon(this, ";"),
        Colon(this, ":"),
        Space(this),
        OpenParen(this, "("),
        CloseParen(this, ")"),
        OpenAngle(this, "<"),
        CloseAngle(this, ">"),
        OpenCurly(this, "{"),
        CloseCurly(this, "}"),
        OpenSquare(this, "["),
        CloseSquare(this, "]"),
        Endline(this),
        StartCluster(this),
        FinishCluster(this)
  {
    ContinuationIndent = GetIndent(2);
  }

  ~AssemblyTextFormatter() override {}

  naclbitc::TokenTextDirective Comma;
  naclbitc::TokenTextDirective Semicolon;
  naclbitc::TokenTextDirective Colon;
  naclbitc::SpaceTextDirective Space;
  naclbitc::OpenTextDirective OpenParen;
  naclbitc::CloseTextDirective CloseParen;
  naclbitc::OpenTextDirective OpenAngle;
  naclbitc::CloseTextDirective CloseAngle;
  naclbitc::OpenTextDirective OpenCurly;
  naclbitc::CloseTextDirective CloseCurly;
  naclbitc::OpenTextDirective OpenSquare;
  naclbitc::CloseTextDirective CloseSquare;
  naclbitc::EndlineTextDirective Endline;
  naclbitc::StartClusteringDirective StartCluster;
  naclbitc::FinishClusteringDirective FinishCluster;

  /// Prints the given type as a sequence of tokens.
  TypeDirective &TokenizeType(Type *Typ) {
    return AllocateTypeDirective(Typ, 0, false);
  }

  /// Prints the named function type as a sequence of tokens.
  /// Typ is the type signature of the function, and FunctionName
  /// points to the name of the function.
  TypeDirective &TokenizeFunctionType(FunctionType *Typ,
                                      BitcodeId *FunctionName) {
    return AllocateTypeDirective(Typ, FunctionName, false);
  }

  /// Prints the function signature of the function type. Typ is
  /// the type signature of the function. FunctionName points to the
  /// name of the function. Note: Unlike TokenizeFunctionType, this
  /// method also adds the parameter names to paramter argumements.
  TypeDirective &TokenizeFunctionSignature(FunctionType *Typ,
                                           BitcodeId *FunctionName) {
    return AllocateTypeDirective(Typ, FunctionName, true);
  }

  /// Prints out the abbreviation defined by Abbrev.
  AbbreviationDirective &TokenizeAbbreviation(NaClBitCodeAbbrev *Abbrev) {
    AbbreviationDirective *Dir = AbbrevDirMemoryPool.Allocate(this);
    Dir->Abbrev = Abbrev;
    return *Dir;
  }

  /// If the record was read using a user-defined abbreviation,
  /// generates assembly tokens describing the abbreviation index
  /// used. Otherwise, no tokens are generated. NumGlobalAbbreviations
  /// is used to determine if the user-defined abbreviation is local
  /// or global.
  AbbrevIndexDirective &TokenizeAbbrevIndex(NaClBitcodeRecord &Record,
                                            unsigned NumGlobalAbbreviations) {
    AbbrevIndexDirective *Dir = AbbrevIndexDirMemoryPool.Allocate(this);
    Dir->Record = &Record;
    Dir->NumGlobalAbbreviations = NumGlobalAbbreviations;
    return *Dir;
  }

private:
  // Converts the given type to tokens, based on the values passed in
  // by TokenizeType, TokenizeFunctionType, or TokenizeFunctionSignature.
  void TokenizeTypeInternal(Type *Typ, BitcodeId* FcnName, bool AddParams);

  // The free list of type directives.
  naclbitc::DirectiveMemoryPool<TypeDirective> TypeDirMemoryPool;

  // Allocates an instance of TypeDirective with the following fields.
  TypeDirective &AllocateTypeDirective(Type *Typ, BitcodeId *FcnId,
                                       bool AddParams);

  // Converts the given abbreviation to tokens.
  void TokenizeAbbreviationInternal(const NaClBitCodeAbbrev *Abbrev);

  // Helper function that prints out the abbreviation expression
  // located at Index in the given abbreviation. Updates Index to
  // next expression in the abbreviation.
  void TokenizeAbbrevExpression(const NaClBitCodeAbbrev *Abbrev,
                                unsigned &Index);

  // Prints out the given abbreviation operator.
  void TokenizeAbbrevOp(const NaClBitCodeAbbrevOp &Op);

  // The free list for abbreviation directives.
  naclbitc::DirectiveMemoryPool<AbbreviationDirective> AbbrevDirMemoryPool;

  // The free list for abbreviation index directives.
  naclbitc::DirectiveMemoryPool<AbbrevIndexDirective> AbbrevIndexDirMemoryPool;

  // Computes how wide the assembly portion of the dump file should be.
  static unsigned GetAssemblyWidth(naclbitc::ObjDumpStream &ObjDump) {
    int Diff = 80 - (ObjDump.GetRecordWidth()+1);
    // Make sure there is enough room to print out assembly.
    return Diff < 20 ? 20 : Diff;
  }
};

void AssemblyTextFormatter::TypeDirective::MyApply(bool Replay) const {
  assert(!Replay && "Shouldn't have been saved for replay");
  AssemblyTextFormatter *AssemblyFormatter =
      reinterpret_cast<AssemblyTextFormatter*>(Formatter);
  AssemblyFormatter->TokenizeTypeInternal(Typ, FcnId, AddParams);
  AssemblyFormatter->TypeDirMemoryPool.Free(const_cast<TypeDirective*>(this));
}

void AssemblyTextFormatter::AbbreviationDirective::MyApply(bool Replay) const {
  assert(!Replay && "Shouldn't have been saved for replay");
  AssemblyTextFormatter *AssemblyFormatter =
      reinterpret_cast<AssemblyTextFormatter*>(Formatter);
  AssemblyFormatter->TokenizeAbbreviationInternal(Abbrev);
  AssemblyFormatter->AbbrevDirMemoryPool.Free(
      const_cast<AbbreviationDirective*>(this));
}

AssemblyTextFormatter::TypeDirective &AssemblyTextFormatter::
AllocateTypeDirective(Type *Typ, BitcodeId *FcnId, bool AddParams) {
  TypeDirective *Element = TypeDirMemoryPool.Allocate(this);
  Element->Init(Typ, FcnId, AddParams);
  return *Element;
}

void AssemblyTextFormatter::TokenizeTypeInternal(
    Type *Typ, BitcodeId* FcnName, bool AddParams) {
  switch (Typ->getTypeID()) {
  case Type::VoidTyID:
    TextStream << "void";
    break;
  case Type::FloatTyID:
    TextStream << "float";
    break;
  case Type::DoubleTyID:
    TextStream << "double";
    break;
  case Type::IntegerTyID:
    TextStream << "i" << Typ->getIntegerBitWidth();
    break;
  case Type::VectorTyID: {
    VectorType *VecType = cast<VectorType>(Typ);
    TextStream << StartCluster << OpenAngle << VecType->getNumElements()
               << Space << "x" << Space
               << TokenizeType(VecType->getElementType())
               << CloseAngle << FinishCluster;
    break;
  }
  case Type::FunctionTyID: {
    FunctionType *FcnType = cast<FunctionType>(Typ);
    unsigned NumParams = FcnType->getFunctionNumParams();
    TextStream << StartCluster
               << TokenizeType(FcnType->getReturnType())
               << Space
               << StartCluster;
    if (NumParams > 0) TextStream << StartCluster;
    if (FcnName) TextStream << *FcnName;
    TextStream << OpenParen << FinishCluster;
    bool HasParamStartCluster = false;
    for (unsigned i = 0, NumParams = FcnType->getFunctionNumParams();
         i < NumParams; ++i) {
      if (i > 0) {
        TextStream << Comma << FinishCluster << Space;
        HasParamStartCluster = false;
      }
      TextStream << StartCluster
                 << TokenizeType(FcnType->getFunctionParamType(i));
      if (AddParams) TextStream << Space << BitcodeId('p', i);
      HasParamStartCluster = true;
    }
    if (FcnType->isFunctionVarArg()) {
      if (HasParamStartCluster) {
        TextStream << Comma << FinishCluster << Space;
      }
      TextStream << StartCluster << "...";
      HasParamStartCluster = true;
    }
    if (HasParamStartCluster) TextStream << FinishCluster;
    TextStream << CloseParen << FinishCluster;
    if (NumParams > 0) TextStream << FinishCluster;
    break;
  }
  default:
    report_fatal_error("Unsupported PNaCl type found");
    break;
  }
}

void AssemblyTextFormatter::TokenizeAbbrevOp(const NaClBitCodeAbbrevOp &Op) {
  // Note: Mimics NaClBitCodeAbbrevOp::Print in NaClBitCodes.cpp
  switch (Op.getEncoding()) {
  case NaClBitCodeAbbrevOp::Literal:
    Tokens() << Op.getValue();
    return;
  case NaClBitCodeAbbrevOp::Fixed:
    Tokens() << StartCluster << "fixed" << OpenParen << Op.getValue()
             << CloseParen << FinishCluster;
    return;
  case NaClBitCodeAbbrevOp::VBR:
    Tokens() << StartCluster << "vbr" << OpenParen << Op.getValue()
             << CloseParen << FinishCluster;
    return;
  case NaClBitCodeAbbrevOp::Array:
    Tokens() << "array";
    return;
  case NaClBitCodeAbbrevOp::Char6:
    Tokens() << "char6";
    return;
  }
}

void AssemblyTextFormatter::
TokenizeAbbrevExpression(const NaClBitCodeAbbrev *Abbrev, unsigned &Index) {
  // Note: Mimics PrintExpression in NaClBitCodes.cpp
  const NaClBitCodeAbbrevOp &Op = Abbrev->getOperandInfo(Index);
  TokenizeAbbrevOp(Op);
  if (unsigned NumArgs = Op.NumArguments()) {
    Tokens() << StartCluster << OpenParen;
    for (unsigned i = 0; i < NumArgs; ++i) {
      ++Index;
      if (i > 0) {
        Tokens() << Comma << FinishCluster << Space << StartCluster;
      }
      TokenizeAbbrevExpression(Abbrev, Index);
    }
    Tokens() << CloseParen << FinishCluster;
  }
}

void AssemblyTextFormatter::
TokenizeAbbreviationInternal(const NaClBitCodeAbbrev *Abbrev) {
  Tokens() << StartCluster << OpenAngle;
  for (unsigned i = 0; i < Abbrev->getNumOperandInfos(); ++i) {
    if (i > 0) {
      Tokens() << Comma << FinishCluster << Space << StartCluster;
    }
    TokenizeAbbrevExpression(Abbrev, i);
  }
  Tokens() << CloseAngle << FinishCluster;
}

void AssemblyTextFormatter::AbbrevIndexDirective::MyApply(bool Replay) const {
  assert(!Replay && "Shouldn't have been saved for replay");
  if (!Record->UsedAnAbbreviation()) return;
  unsigned Index = Record->GetAbbreviationIndex();
  if (Index < naclbitc::FIRST_APPLICATION_ABBREV) return;
  Index -= naclbitc::FIRST_APPLICATION_ABBREV;
  bool IsGlobal = Index < NumGlobalAbbreviations;
  if (!IsGlobal) Index -= NumGlobalAbbreviations;
  BitcodeId AbbrevIndex('a', Index, IsGlobal);
  AssemblyTextFormatter *Fmtr =
      reinterpret_cast<AssemblyTextFormatter*>(Formatter);
  Tokens() << Fmtr->Space << Fmtr->StartCluster << Fmtr->OpenAngle
           << AbbrevIndex << Fmtr->CloseAngle << Fmtr->FinishCluster;
  Fmtr->AbbrevIndexDirMemoryPool.Free(const_cast<AbbrevIndexDirective*>(this));
}

// Holds possible alignements for loads/stores etc. Used to extract
// expected values.
static unsigned NaClPossibleLoadStoreAlignments[] = {
  1, 2, 4, 8
};

// Finds the expected alignments for the load/store, for type Ty.
static void NaClGetExpectedLoadStoreAlignment(
    const DataLayout &DL, Type *Ty, std::vector<unsigned> &ValidAlignments) {
  for (size_t i = 0; i < array_lengthof(NaClPossibleLoadStoreAlignments); ++i) {
    unsigned Alignment = NaClPossibleLoadStoreAlignments[i];
    if (PNaClABIProps::isAllowedAlignment(&DL, Alignment, Ty)) {
      ValidAlignments.push_back(Alignment);
    }
  }
}

/// Top-level class to parse bitcode file and transform to
/// corresponding disassembled code.
class NaClDisTopLevelParser : public NaClBitcodeParser {
  NaClDisTopLevelParser(const NaClDisTopLevelParser&) = delete;
  void operator=(const NaClDisTopLevelParser&) = delete;

public:
  NaClDisTopLevelParser(NaClBitcodeHeader &Header,
                        NaClBitstreamCursor &Cursor,
                        naclbitc::ObjDumpStream &ObjDump)
      : NaClBitcodeParser(Cursor),
        Mod("ObjDump", getGlobalContext()),
        ObjDump(ObjDump),
        AbbrevListener(this),
        DL(&Mod),
        AllowedIntrinsics(&Mod.getContext()),
        AssemblyFormatter(ObjDump),
        Header(Header),
        NumFunctions(0),
        NumGlobals(0),
        ExpectedNumGlobals(0),
        NumParams(0),
        NumConstants(0),
        NumValuedInsts(0),
        UnknownType(Type::getVoidTy(Mod.getContext())),
        PointerType(Type::getInt32Ty(Mod.getContext())),
        ComparisonType(Type::getInt1Ty(Mod.getContext())),
        NumDefinedFunctions(0) {
    SetListener(&AbbrevListener);
  }

  ~NaClDisTopLevelParser() override {
    // Be sure to flush any remaining errors.
    ObjDump.Flush();
  }

  // Returns the number of errors that were sent to the ObjDump.
  unsigned GetNumErrors() {
    return ObjDump.GetNumErrors();
  }

  /// Generates an error with the given message.
  bool ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit,
               const std::string &Message) final {
    ObjDump.ErrorAt(Level, Bit) << Message << "\n";
    if (Level == naclbitc::Fatal)
      ObjDump.FlushThenQuit();
    return true;
  }

  /// Parses the top-level module block.
  bool ParseBlock(unsigned BlockID) override;

  /// Installs the given type to the next available type index.
  void InstallType(Type *Ty) {
    TypeIdType.push_back(Ty);
  }

  /// Returns the type associated with the given type index.
  Type *GetType(uint32_t Index) {
    if (Index >= TypeIdType.size()) {
      BitcodeId Id('t', Index);
      Errors() << "Can't find definition for " << Id << "\n";
      // Recover so that additional errors can be found.
      return UnknownType;
    }
    return TypeIdType[Index];
  }

  /// Returns the number of types (currently) defined in the bitcode
  /// file.
  uint32_t GetNumTypes() const {
    return TypeIdType.size();
  }

  /// Returns true if Type represents a (non-zero sized) value.
  bool isValidValueType(Type *Ty) const {
    return Ty->isIntegerTy() || Ty->isFloatTy() || Ty->isDoubleTy()
        || Ty->isVectorTy();
  }

  /// Installs the given type to the next available function index.
  void InstallFunctionType(FunctionType *Ty, uint64_t BitAddress) {
    assert(FunctionIdType.size() == NumFunctions);
    ++NumFunctions;
    FunctionIdType.push_back(Ty);
    FunctionIdAddress.push_back(BitAddress);
    // Let Valuesymtab change this to true if appropriate.
    FunctionIdIsIntrinsic.push_back(false);
  }

  /// Returns the bit address where the function record appeared in
  /// the bitcode file. Returns 0 if unknown.
  uint64_t GetFunctionIdAddress(uint32_t Index) {
    if (Index >= FunctionIdAddress.size()) return 0;
    return FunctionIdAddress[Index];
  }

  /// Sets the record bit address to the function ID address (if known).
  void SetRecordAddressToFunctionIdAddress(uint32_t Index) {
    uint64_t Address = GetFunctionIdAddress(Index);
    if (Address)
      ObjDump.SetRecordBitAddress(Address);
  }

  //// Returns the type associated with the given function index.
  FunctionType *GetFunctionType(uint32_t Index) {
    if (Index >= FunctionIdType.size()) {
      BitcodeId Id('f', Index);
      Errors() << "Can't find definition for " << Id << "\n";
      Fatal();
    }
    return FunctionIdType[Index];
  }

  /// Marks the function associated with the given Index as intrinsic.
  void MarkFunctionAsIntrinsic(uint32_t Index) {
    if (Index >= FunctionIdIsIntrinsic.size()) {
      BitcodeId Id('f', Index);
      Errors() << "Can't define " << Id << " as intrinsic, no definition";
    }
    FunctionIdIsIntrinsic[Index] = true;
  }

  /// Returns true if the given Index is for a function intrinsic.
  bool IsFunctionIntrinsic(uint32_t Index) {
    if (Index >= FunctionIdIsIntrinsic.size()) return false;
    return FunctionIdIsIntrinsic[Index];
  }

  /// Returns true if the function is an intrinsic function.
  bool IsIntrinsicAllowed(const std::string &FuncName,
                          const FunctionType *FuncType) {
    return AllowedIntrinsics.isAllowed(FuncName, FuncType);
  }

  /// Returns the type of the Name'd intrinsic, if defined as an
  /// allowed intrinsic name. Otherwise returns 0.
  FunctionType *GetIntrinsicType(const std::string &Name) {
    return AllowedIntrinsics.getIntrinsicType(Name);
  }

  /// Returns the number of functions (currently) defined/declared in
  /// the bitcode file.
  uint32_t GetNumFunctions() const {
    return NumFunctions;
  }

  /// Installs that the given function index as having a function body
  /// (i.e. the function address uses the "define" keyword instead of
  /// the "declare" keyword).
  void InstallDefinedFunction(uint32_t Index) {
    DefinedFunctions.push_back(Index);
  }

  /// Returns true if there is an Index defined function block.
  bool HasDefinedFunctionIndex(uint32_t Index) const {
    return Index < DefinedFunctions.size();
  }

  /// Returns the function index associated with the Index defined
  /// function block.
  uint32_t GetDefinedFunctionIndex(uint32_t Index) const {
    assert(Index < DefinedFunctions.size());
    return DefinedFunctions[NumDefinedFunctions];
  }

  /// Returns true if there is a next defined function index.
  bool HasNextDefinedFunctionIndex() const {
    return HasDefinedFunctionIndex(NumDefinedFunctions);
  }

  /// Returns the function index associated with the next defined function.
  uint32_t GetNextDefinedFunctionIndex() const {
    return GetDefinedFunctionIndex(NumDefinedFunctions);
  }

  /// Returns true if the given value ID corresponds to a declared (rather
  /// than defined) function.
  bool IsDeclaredFunction(uint32_t Index) {
    if (Index >= NumFunctions) return false;
    for (size_t i = 0, e = DefinedFunctions.size(); i < e; ++i) {
      if (DefinedFunctions[i] == Index) return false;
    }
    return true;
  }

  /// Increments the number of (currently) defined functions in the
  /// bitcode file by one.
  void IncNumDefinedFunctions() {
    ++NumDefinedFunctions;
  }

  void IncNumGlobals() {
    NumGlobals++;
  }

  /// Returns the number of globals (currently) defined in the bitcode
  /// file.
  uint32_t GetNumGlobals() const {
    return NumGlobals;
  }

  /// Returns the expected number of globals (as defined by the count
  /// record of the globals block).
  uint32_t GetExpectedNumGlobals() const {
    return ExpectedNumGlobals;
  }

  /// Sets field ExpectedNumGlobals to the given value.
  void SetExpectedNumGlobals(uint32_t NewValue) {
    ExpectedNumGlobals = NewValue;
  }

  /// Installs the given type to the next available parameter index.
  void InstallParamType(Type *Ty) {
    while (ParamIdType.size() <= NumParams) {
      ParamIdType.push_back(UnknownType);
    }
    ParamIdType[NumParams++] = Ty;
  }

  /// Returns the type associated with the given parameter index.
  Type *GetParamType(uint32_t Index) {
    if (Index >= ParamIdType.size()) {
      BitcodeId Id('p', Index);
      Errors() << "Can't find defintion for " << Id << "\n";
      Fatal();
    }
    return ParamIdType[Index];
  }

  /// Returns the number of parameters (currently) defined in the
  /// enclosing defined function.
  uint32_t GetNumParams() const {
    return NumParams;
  }

  /// Installs the given type to the next available constant index.
  void InstallConstantType(Type *Ty) {
    while (ConstantIdType.size() <= NumConstants) {
      ConstantIdType.push_back(UnknownType);
    }
    ConstantIdType[NumConstants++] = Ty;
  }

  /// Returns the type associated with the given constant index.
  Type *GetConstantType(uint32_t Index) {
    if (Index >= ConstantIdType.size()) {
      BitcodeId Id('c', Index);
      Errors() << "Can't find definition for " << Id << "\n";
      Fatal();
    }
    return ConstantIdType[Index];
  }

  /// Returns the number of constants (currently) defined in the
  /// enclosing defined function.
  uint32_t GetNumConstants() const {
    return NumConstants;
  }

  /// Installs the given type to the given instruction index.  Note:
  /// Instruction indices are only associated with instructions that
  /// generate values.
  void InstallInstType(Type *Ty, uint32_t Index) {
    while (InstIdType.size() <= Index) {
      InstIdType.push_back(UnknownType);
    }
    if (InstIdType[Index] != UnknownType && Ty != InstIdType[Index]) {
      Errors() << BitcodeId('v', Index) << " defined with multiple types: "
               << *Ty << " and " << *InstIdType[Index] << "\n";
    }
    InstIdType[Index] = Ty;
  }

  /// Installs the given type to the next available instruction index.
  void InstallInstType(Type *Ty) {
    InstallInstType(Ty, NumValuedInsts++);
  }

  /// Returns the type associated with the given instruction index.
  /// Note: Instruction indices are only associated with instructions
  /// that generate values.
  Type *GetInstType(uint32_t Index) {
    if (Index >= InstIdType.size()) {
      Errors() << "Can't find type for " << BitcodeId('v', Index) << "\n";
      return UnknownType;
    }
    return InstIdType[Index];
  }

  /// Returns the number of instructions (in the defined function)
  /// that (currently) generate values.
  uint32_t GetNumValuedInstructions() const {
    return NumValuedInsts;
  }

  /// Resets index counters local to a defined function.
  void ResetLocalCounters() {
    ParamIdType.clear();
    NumParams = 0;
    NumConstants = 0;
    InstIdType.clear();
    NumValuedInsts = 0;
  }

  /// Returns the bitcode id associated with the absolute value index
  BitcodeId GetBitcodeId(uint32_t Index);

  /// Returns the type associated with the given absolute value index.
  /// If UnderlyingType is false, function indices always return a
  /// pointer type. Otherwise, function indices returns the declared
  /// type of the function index.
  Type *GetValueType(uint32_t Index, bool UnderlyingType = false);

  /// Returns a type to use when the type is unknown.
  Type *GetUnknownType() const {
    return UnknownType;
  }

  /// Returns the type used to represent a pointer.
  Type *GetPointerType() const {
    return PointerType;
  }

  /// Returns the type used to represent comparison results.
  Type *GetComparisonType() const {
    return ComparisonType;
  }

  /// Returns the void type.
  Type *GetVoidType() const {
    return Type::getVoidTy(getGlobalContext());
  }

  /// Returns the float (32-bit) type.
  Type *GetFloatType() const {
    return Type::getFloatTy(getGlobalContext());
  }

  /// Returns the double (64-bit) type.
  Type *GetDoubleType() const {
    return Type::getDoubleTy(getGlobalContext());
  }

  /// Returns an integer type of N bits.
  Type *GetIntegerType(unsigned N) const {
    return Type::getIntNTy(getGlobalContext(), N);
  }

  /// Returns the number of defined global abbreviations (currently)
  /// for the given block id.
  unsigned GetNumGlobalAbbreviations(unsigned BlockID) {
    return GlobalAbbrevsCountMap[BlockID];
  }

  /// Increments the current number of defined global abbreviations.
  void IncNumGlobalAbbreviations(unsigned BlockID) {
    ++GlobalAbbrevsCountMap[BlockID];
  }

  /// Verifies the given integer operator has the right type.  Returns
  /// the operator.
  const char *VerifyIntArithmeticOp(const char *Op, Type *OpTy) {
    if (!IgnorePNaClABIChecks &&
        !PNaClABITypeChecker::isValidIntArithmeticType(OpTy)) {
      Errors() << Op << ": Invalid integer arithmetic type: " << *OpTy;
    }
    return Op;
  }

  // Checks the Alignment for loading/storing a value of type Ty. If
  // invalid, generates an appropriate error message.
  void VerifyMemoryAccessAlignment(const char *Op, Type *Ty,
                                   unsigned Alignment) {
    if (IgnorePNaClABIChecks) return;
    if (!PNaClABIProps::isAllowedAlignment(&DL, Alignment, Ty)) {
      raw_ostream &Errs = Errors();
      std::vector<unsigned> Alignments;
      NaClGetExpectedLoadStoreAlignment(DL, Ty, Alignments);
      if (!Alignments.empty()) {
        Errs << Op << ": Illegal alignment for " << *Ty << ". Expects: ";
        bool isFirst = true;
        for (auto Align : Alignments) {
          if (isFirst)
            isFirst = false;
          else
            Errs << " or ";
          Errs << Align;
        }
        Errs << "\n";
      } else {
        Errs << Op << ": Not allowed for type: " << *Ty << "\n";
      }
    }
  }

  // ******************************************************
  // The following return the corresponding methods/fields
  // from the the assembly formatter/objdumper.
  // ******************************************************

  naclbitc::TokenTextDirective &Semicolon() {
    return AssemblyFormatter.Semicolon;
  }

  naclbitc::TokenTextDirective &Colon() {
    return AssemblyFormatter.Colon;
  }

  naclbitc::SpaceTextDirective &Space() {
    return AssemblyFormatter.Space;
  }

  naclbitc::TokenTextDirective &Comma() {
    return AssemblyFormatter.Comma;
  }

  naclbitc::OpenTextDirective &OpenParen() {
    return AssemblyFormatter.OpenParen;
  }

  naclbitc::CloseTextDirective &CloseParen() {
    return AssemblyFormatter.CloseParen;
  }

  naclbitc::OpenTextDirective &OpenAngle() {
    return AssemblyFormatter.OpenAngle;
  }

  naclbitc::CloseTextDirective &CloseAngle() {
    return AssemblyFormatter.CloseAngle;
  }

  naclbitc::OpenTextDirective &OpenCurly() {
    return AssemblyFormatter.OpenCurly;
  }

  naclbitc::CloseTextDirective &CloseCurly() {
    return AssemblyFormatter.CloseCurly;
  }

  naclbitc::OpenTextDirective &OpenSquare() {
    return AssemblyFormatter.OpenSquare;
  }

  naclbitc::CloseTextDirective &CloseSquare() {
    return AssemblyFormatter.CloseSquare;
  }

  naclbitc::EndlineTextDirective &Endline() {
    return AssemblyFormatter.Endline;
  }

  naclbitc::StartClusteringDirective &StartCluster() {
    return AssemblyFormatter.StartCluster;
  }

  naclbitc::FinishClusteringDirective &FinishCluster() {
    return AssemblyFormatter.FinishCluster;
  }

  raw_ostream &Tokens() {
    return AssemblyFormatter.Tokens();
  }

  raw_ostream &Errors() {
    return ObjDump.Error();
  }

  raw_ostream &Warnings() {
    if (ReportWarningsAsErrors) return Errors();
    return ObjDump.Warning();
  }

  const std::string &GetAssemblyIndent() const {
    return AssemblyFormatter.GetIndent();
  }

  unsigned GetAssemblyNumTabs() const {
    return AssemblyFormatter.GetNumTabs();
  }

  void IncAssemblyIndent() {
    AssemblyFormatter.Inc();
  }

  void DecAssemblyIndent() {
    AssemblyFormatter.Dec();
  }

  void IncRecordIndent() {
    ObjDump.IncRecordIndent();
  }

  void DecRecordIndent() {
    ObjDump.DecRecordIndent();
  }

  void ObjDumpFlush() {
    ObjDump.Flush();
  }

  void ObjDumpSetRecordBitAddress(uint64_t Bit) {
    ObjDump.SetRecordBitAddress(Bit);
  }

  void ObjDumpWrite(uint64_t Bit,
                    const NaClBitcodeRecordData &Record,
                    int32_t AbbrevIndex =
                    naclbitc::ABBREV_INDEX_NOT_SPECIFIED) {
    ObjDump.Write(Bit, Record, AbbrevIndex);
  }

  void ObjDumpWrite(uint64_t Bit,
                    const NaClBitcodeRecord &Record) {
    ObjDump.Write(Bit, Record.GetRecordData(), Record.GetAbbreviationIndex());
  }

  AssemblyTextFormatter::TypeDirective &
  TokenizeType(Type *Typ) {
    return AssemblyFormatter.TokenizeType(Typ);
  }

  AssemblyTextFormatter::TypeDirective &
  TokenizeFunctionType(FunctionType *Type, BitcodeId *FcnId) {
    return AssemblyFormatter.TokenizeFunctionType(Type, FcnId);
  }

  AssemblyTextFormatter::TypeDirective &
  TokenizeFunctionSignature(FunctionType *Typ, BitcodeId *FcnId) {
    return AssemblyFormatter.TokenizeFunctionSignature(Typ, FcnId);
  }

  AssemblyTextFormatter::AbbreviationDirective &
  TokenizeAbbreviation(NaClBitCodeAbbrev *Abbrev) {
    return AssemblyFormatter.TokenizeAbbreviation(Abbrev);
  }

  AssemblyTextFormatter::AbbrevIndexDirective &
  TokenizeAbbrevIndex(NaClBitcodeRecord &Record,
                      unsigned NumGlobalAbbreviations) {
    return AssemblyFormatter.TokenizeAbbrevIndex(Record,
                                                 NumGlobalAbbreviations);
  }

private:
  // A placeholder module for associating context and data layout.
  Module Mod;
  // The output stream to generate disassembly into.
  naclbitc::ObjDumpStream &ObjDump;
  // Listener used to get abbreviations as they are read.
  NaClBitcodeParserListener AbbrevListener;
  // DataLayout to use.
  const DataLayout DL;
  // The set of allowed intrinsics.
  PNaClAllowedIntrinsics AllowedIntrinsics;
  // The formatter to use to format assembly code.
  AssemblyTextFormatter AssemblyFormatter;
  // The header appearing before the beginning of the input stream.
  NaClBitcodeHeader &Header;
  // The list of known types (index i defines the type associated with
  // type index i).
  std::vector<Type*> TypeIdType;
  // The list of known function signatures (index i defines the type
  // signature associated with function index i).
  std::vector<FunctionType*> FunctionIdType;
  // boolean flag defining if function id is an intrinsic.
  std::vector<bool> FunctionIdIsIntrinsic;
  // The list of record bit addresses associated with corresponding
  // declaration of function IDs.
  std::vector<uint64_t> FunctionIdAddress;
  // The number of function indices currently defined.
  uint32_t NumFunctions;
  // The number of global indices currently defined.
  uint32_t NumGlobals;
  // The expected number of global indices (i.e. value of count record
  // in the globals block).
  uint32_t ExpectedNumGlobals;
  // The list of known parameter types (index i defines the type
  // associated with parameter index i).
  std::vector<Type*>ParamIdType;
  // The number of parameter indices currently defined.
  uint32_t NumParams;
  std::vector<Type*>ConstantIdType;
  // The number of constant indices currently defined.
  uint32_t NumConstants;
  // The list of known instruction types (index i defines the type
  // associated with valued instruction index i).
  std::vector<Type*> InstIdType;
  // The number of valued instructions currently defined.
  uint32_t NumValuedInsts;
  // Models an unknown type.
  Type *UnknownType;
  // Models the pointer type.
  Type *PointerType;
  // Models a result of a comparison.
  Type *ComparisonType;
  // Keeps list of function indicies (in the order found in the bitcode)
  // that correspond to defined functions.
  std::vector<uint32_t> DefinedFunctions;
  // The number of function indices currently known to be defined.
  uint32_t NumDefinedFunctions;
  // Holds the number of global abbreviations defined for each block.
  std::map<unsigned, unsigned> GlobalAbbrevsCountMap;
};

BitcodeId NaClDisTopLevelParser::GetBitcodeId(uint32_t Index) {
  if (Index < NumFunctions) {
    return BitcodeId('f', Index);
  }
  Index -= NumFunctions;
  if (Index < ExpectedNumGlobals) {
    return BitcodeId('g', Index);
  }
  Index -= ExpectedNumGlobals;
  if (Index < NumParams) {
    return BitcodeId('p', Index);
  }
  Index -= NumParams;
  if (Index < NumConstants) {
    return BitcodeId('c', Index);
  }
  Index -= NumConstants;
  return BitcodeId('v', Index);
}

Type *NaClDisTopLevelParser::GetValueType(uint32_t Index, bool UnderlyingType) {
  uint32_t Idx = Index;
  if (Idx < NumFunctions)
    return UnderlyingType ? GetFunctionType(Idx) : PointerType;
  Idx -= NumFunctions;
  if (Idx < ExpectedNumGlobals)
    return PointerType;
  Idx -= ExpectedNumGlobals;
  if (Idx < NumParams)
    return GetParamType(Idx);
  Idx -= NumParams;
  if (Idx < NumConstants)
    return GetConstantType(Idx);
  Idx -= NumConstants;
  return GetInstType(Idx);
}

// Base class of all block parsers for the bitcode file. Handles
// common actions needed by derived blocks.
//
// Note: This class also handles blocks with unknown block ID's.
class NaClDisBlockParser : public NaClBitcodeParser {
protected:
  /// Constructor for the top-level block parser.
  NaClDisBlockParser(unsigned BlockID, NaClDisTopLevelParser *Context)
      : NaClBitcodeParser(BlockID, Context),
        Context(Context){
    InitAbbreviations();
  }

  /// Constructor for nested block parsers.
  NaClDisBlockParser(unsigned BlockID, NaClDisBlockParser *EnclosingParser)
      : NaClBitcodeParser(BlockID, EnclosingParser),
        Context(EnclosingParser->Context) {
    InitAbbreviations();
  }

public:

  ~NaClDisBlockParser() override {
    // Be sure to flush any remaining errors reported at end of block.
    ObjDumpFlush();
  }

  bool ParseBlock(unsigned BlockID) override;

protected:
  void EnterBlock(unsigned NumWords) override;

  void ExitBlock() override;

  void ProcessRecord() override;

  void ProcessAbbreviation(unsigned BlockID, NaClBitCodeAbbrev *Abbrev,
                           bool IsLocal) override;

  void InitAbbreviations() {
    NumGlobalAbbreviations = Context->GetNumGlobalAbbreviations(GetBlockID());
    NumLocalAbbreviations = 0;
  }

  // Prints the block header instruction for the block. Called by EnterBlock.
  virtual void PrintBlockHeader();

  // Dumps the corresponding record for a block enter.
  void DumpEnterBlockRecord();

  // Returns the identifier for the next local abbreviation appearing in
  // the block.
  BitcodeId NextLocalAbbreviationId() {
    return BitcodeId('a', NumLocalAbbreviations, false);
  }

  AssemblyTextFormatter::AbbrevIndexDirective &TokenizeAbbrevIndex() {
    return Context->TokenizeAbbrevIndex(Record, NumGlobalAbbreviations);
  }

  // *****************************************************************
  // The following are dispatching methods that call the corresponding
  // method on the Context (i.e. NaClDisTopLevelParser).
  // *****************************************************************

  /// Returns a directive to tokenize the given type.
  AssemblyTextFormatter::TypeDirective &TokenizeType(Type *Type) {
    return Context->TokenizeType(Type);
  }

  /// Returns a directive to tokenize the given function type,
  /// using the given function id.
  AssemblyTextFormatter::TypeDirective
  &TokenizeFunctionType(FunctionType *Type, BitcodeId *FcnId) {
    return Context->TokenizeFunctionType(Type, FcnId);
  }

  /// Returns a directive to tokenize the function signature, given the
  /// type of the function signature, and the given function id.
  AssemblyTextFormatter::TypeDirective
  &TokenizeFunctionSignature(FunctionType *Typ, BitcodeId *FcnId) {
    return Context->TokenizeFunctionSignature(Typ, FcnId);
  }

  AssemblyTextFormatter::AbbreviationDirective &TokenizeAbbreviation(
      NaClBitCodeAbbrev *Abbrev) {
    return Context->TokenizeAbbreviation(Abbrev);
  }

  naclbitc::TokenTextDirective &Semicolon() {
    return Context->Semicolon();
  }

  naclbitc::TokenTextDirective &Colon() {
    return Context->Colon();
  }

  naclbitc::SpaceTextDirective &Space() {
    return Context->Space();
  }

  naclbitc::TokenTextDirective &Comma() {
    return Context->Comma();
  }

  naclbitc::OpenTextDirective &OpenParen() {
    return Context->OpenParen();
  }


  naclbitc::CloseTextDirective &CloseParen() {
    return Context->CloseParen();
  }

  naclbitc::OpenTextDirective &OpenAngle() {
    return Context->OpenAngle();
  }

  naclbitc::CloseTextDirective &CloseAngle() {
    return Context->CloseAngle();
  }

  naclbitc::OpenTextDirective &OpenCurly() {
    return Context->OpenCurly();
  }

  naclbitc::CloseTextDirective &CloseCurly() {
    return Context->CloseCurly();
  }

  naclbitc::OpenTextDirective &OpenSquare() {
    return Context->OpenSquare();
  }

  naclbitc::CloseTextDirective &CloseSquare() {
    return Context->CloseSquare();
  }

  naclbitc::EndlineTextDirective &Endline() {
    return Context->Endline();
  }

  naclbitc::StartClusteringDirective &StartCluster() {
    return Context->StartCluster();
  }

  naclbitc::FinishClusteringDirective &FinishCluster() {
    return Context->FinishCluster();
  }

  raw_ostream &Tokens() {
    return Context->Tokens();
  }

  raw_ostream &Errors() {
    return Context->Errors();
  }

  raw_ostream &Warnings() {
    return Context->Warnings();
  }

  bool ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit,
               const std::string &Message) final {
    return Context->ErrorAt(Level, Bit, Message);
  }

  const std::string &GetAssemblyIndent() const {
    return Context->GetAssemblyIndent();
  }

  unsigned GetAssemblyNumTabs() const {
    return Context->GetAssemblyNumTabs();
  }

  void IncAssemblyIndent() {
    Context->IncAssemblyIndent();
  }

  void DecAssemblyIndent() {
    Context->DecAssemblyIndent();
  }

  void IncRecordIndent() {
    Context->IncRecordIndent();
  }

  void DecRecordIndent() {
    Context->DecRecordIndent();
  }

  void ObjDumpFlush() {
    Context->ObjDumpFlush();
  }

  void ObjDumpWrite(uint64_t Bit,
                    const NaClBitcodeRecordData &Record,
                    int32_t AbbrevIndex =
                    naclbitc::ABBREV_INDEX_NOT_SPECIFIED) {
    Context->ObjDumpWrite(Bit, Record, AbbrevIndex);
  }

  void ObjDumpWrite(uint64_t Bit,
                    const NaClBitcodeRecord &Record) {
    Context->ObjDumpWrite(Bit, Record);
  }

  void ObjDumpSetRecordBitAddress(uint64_t Bit) {
    Context->ObjDumpSetRecordBitAddress(Bit);
  }

  void InstallType(Type *Ty) {
    Context->InstallType(Ty);
  }

  Type *GetType(uint32_t Index) {
    return Context->GetType(Index);
  }

  uint32_t GetNumTypes() const {
    return Context->GetNumTypes();
  }

  bool isValidValueType(Type *Ty) const {
    return Context->isValidValueType(Ty);
  }

  FunctionType *GetFunctionType(uint32_t Index) {
    return Context->GetFunctionType(Index);
  }

  uint32_t GetNumFunctions() const {
    return Context->GetNumFunctions();
  }

  void IncNumGlobals() {
    Context->IncNumGlobals();
  }

  uint32_t GetNumGlobals() const {
    return Context->GetNumGlobals();
  }

  void InstallFunctionType(FunctionType *Ty) {
    return Context->InstallFunctionType(Ty, Record.GetStartBit());
  }

  void InstallDefinedFunction(uint32_t Index) {
    Context->InstallDefinedFunction(Index);
  }

  BitcodeId GetBitcodeId(uint32_t Id) {
    return Context->GetBitcodeId(Id);
  }

  void InstallParamType(Type *Ty) {
    Context->InstallParamType(Ty);
  }

  uint32_t GetNumParams() const {
    return Context->GetNumParams();
  }
  void InstallConstantType(Type *ConstantType) {
    Context->InstallConstantType(ConstantType);
  }

  Type *GetConstantType(uint32_t Index) {
    return Context->GetConstantType(Index);
  }

  uint32_t GetNumConstants() const {
    return Context->GetNumConstants();
  }

  void InstallInstType(Type *Ty, uint32_t Index) {
    Context->InstallInstType(Ty, Index);
  }

  void InstallInstType(Type *Ty) {
    Context->InstallInstType(Ty);
  }

  uint32_t GetNumValuedInstructions() const {
    return Context->GetNumValuedInstructions();
  }

  Type *GetValueType(uint32_t Id, bool UnderlyingType = false) {
    return Context->GetValueType(Id, UnderlyingType);
  }

  Type *GetFunctionValueType(uint32_t Id) {
    return GetValueType(Id, /* UnderlyingType = */ true);
  }

  Type *GetUnknownType() const {
    return Context->GetUnknownType();
  }

  Type *GetPointerType() const {
    return Context->GetPointerType();
  }

  Type *GetComparisonType() const {
    return Context->GetComparisonType();
  }

  Type *GetVoidType() const {
    return Context->GetVoidType();
  }

  Type *GetFloatType() const {
    return Context->GetFloatType();
  }

  Type *GetDoubleType() const {
    return Context->GetDoubleType();
  }

  Type *GetIntegerType(unsigned Size) const {
    return Context->GetIntegerType(Size);
  }

  const char *VerifyIntArithmeticOp(const char *Op, Type *OpTy) {
    return Context->VerifyIntArithmeticOp(Op, OpTy);
  }

protected:
  // The context parser that contains decoding state.
  NaClDisTopLevelParser *Context;
  // The number of global abbreviations defined for this block.
  unsigned NumGlobalAbbreviations;
  // The current number of local abbreviations defined for this block.
  unsigned NumLocalAbbreviations;
};

bool NaClDisBlockParser::ParseBlock(unsigned BlockId) {
  // Only called if we don't know the details about the block.
  ObjDumpSetRecordBitAddress(GetBlock().GetStartBit());
  Errors() << "Don't know how to parse block " << BlockId
           << ", when in block " << GetBlockID() << "\n";
  NaClDisBlockParser Parser(BlockId, this);
  return Parser.ParseThisBlock();
}

void NaClDisBlockParser::PrintBlockHeader() {
  Errors() << "Unknown block id found: " << GetBlockID() << "\n";
  Tokens() << "unknown" << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = "
           << GetBlockID() << Endline();
}

void NaClDisBlockParser::EnterBlock(unsigned NumWords) {
  PrintBlockHeader();
  DumpEnterBlockRecord();
  IncRecordIndent();
  IncAssemblyIndent();
}

void NaClDisBlockParser::ExitBlock() {
  DecAssemblyIndent();
  DecRecordIndent();
  Tokens() << CloseCurly() << Endline();
  NaClBitcodeRecordData Exit;
  Exit.Code = naclbitc::BLK_CODE_EXIT;
  ObjDumpWrite(Record.GetStartBit(), Exit, naclbitc::END_BLOCK);
}

void NaClDisBlockParser::DumpEnterBlockRecord() {
  // TODO(kschimpf): Better integrate this with the bitstream reader
  // (which currently doesn't build any records).
  NaClBitcodeRecordData Enter;
  Enter.Code = naclbitc::BLK_CODE_ENTER;
  Enter.Values.push_back(GetBlockID());
  Enter.Values.push_back(Record.GetCursor().getAbbrevIDWidth());
  ObjDumpWrite(GetBlock().GetStartBit(), Enter, naclbitc::ENTER_SUBBLOCK);
}

void NaClDisBlockParser::ProcessAbbreviation(unsigned BlockID,
                                             NaClBitCodeAbbrev *Abbrev,
                                             bool IsLocal) {
  Tokens() << NextLocalAbbreviationId() << Space() << "=" << Space()
           << "abbrev" << Space() << TokenizeAbbreviation(Abbrev)
           << Semicolon() << Endline();
  ++NumLocalAbbreviations;
  ObjDumpWrite(Record.GetStartBit(), Record);
}

void NaClDisBlockParser::ProcessRecord() {
  // Note: Only called if block is not understood. Hence, we
  // only report the records.
  ObjDumpWrite(Record.GetStartBit(), Record);
}

/// Parses and disassembles the blockinfo block.
class NaClDisBlockInfoParser : public NaClDisBlockParser {
public:
  NaClDisBlockInfoParser(unsigned BlockID,
                         NaClDisBlockParser *EnclosingParser)
      : NaClDisBlockParser(BlockID, EnclosingParser) {
  }

  ~NaClDisBlockInfoParser() override {}

private:
  void PrintBlockHeader() override;

  void SetBID() override;

  void ProcessAbbreviation(unsigned BlockID, NaClBitCodeAbbrev *Abbrev,
                           bool IsLocal) override;

  /// Returns the abbreviation id for the next global abbreviation
  /// to be defined for the given block id.
  BitcodeId NextGlobalAbbreviationId(unsigned BlockID) {
    return BitcodeId('a', Context->GetNumGlobalAbbreviations(BlockID), true);
  }
};

void NaClDisBlockInfoParser::PrintBlockHeader() {
  Tokens() << "abbreviations" << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = "
           << GetBlockID() << Endline();
}

void NaClDisBlockInfoParser::SetBID() {
  std::string BlockName;
  uint64_t BlockID = Record.GetValues()[0];
  switch (BlockID) {
  case naclbitc::MODULE_BLOCK_ID:
    Tokens() << "module";
    break;
  case naclbitc::CONSTANTS_BLOCK_ID:
    Tokens() << "constants";
    break;
  case naclbitc::FUNCTION_BLOCK_ID:
    Tokens() << "function";
    break;
  case naclbitc::VALUE_SYMTAB_BLOCK_ID:
    Tokens() << "valuesymtab";
    break;
  case naclbitc::TYPE_BLOCK_ID_NEW:
    Tokens() << "types";
    break;
  case naclbitc::GLOBALVAR_BLOCK_ID:
    Tokens() << "globals";
    break;
  default:
    Tokens() << "block" << OpenParen() << BlockID << CloseParen();
    Errors() << "Block id " << BlockID << " not understood.\n";
    break;
  }
  Tokens() << Colon() << Endline();
  ObjDumpWrite(Record.GetStartBit(), Record);
}

void NaClDisBlockInfoParser::ProcessAbbreviation(unsigned BlockID,
                                                 NaClBitCodeAbbrev *Abbrev,
                                                 bool IsLocal) {
  IncAssemblyIndent();
  Tokens() << NextGlobalAbbreviationId(BlockID) << Space() << "=" << Space()
           << "abbrev" << Space() << TokenizeAbbreviation(Abbrev)
           << Semicolon() << Endline();
  Context->IncNumGlobalAbbreviations(BlockID);
  DecAssemblyIndent();
  ObjDumpWrite(Record.GetStartBit(), Record);
}

/// Parses and disassembles the types block.
class NaClDisTypesParser : public NaClDisBlockParser {
public:
  NaClDisTypesParser(unsigned BlockID,
                     NaClDisBlockParser *EnclosingParser)
      : NaClDisBlockParser(BlockID, EnclosingParser),
        ExpectedNumTypes(0),
        IsFirstRecord(true)
  {
  }

  ~NaClDisTypesParser() override;

private:
  void PrintBlockHeader() override;

  void ProcessRecord() override;

  /// Returns the value id for the next type to be defined.
  BitcodeId NextTypeId() {
    return BitcodeId('t', GetNumTypes());
  }

  // Installs unknown type as definition of next type.
  void InstallUnknownTypeForNextId();


  uint32_t ExpectedNumTypes;
  bool IsFirstRecord;
};

NaClDisTypesParser::~NaClDisTypesParser() {
  if (GetNumTypes() != ExpectedNumTypes) {
    Errors() << "Expected " << ExpectedNumTypes << " types but found: "
             << GetNumTypes() << "\n";
  }
}

void NaClDisTypesParser::PrintBlockHeader() {
  Tokens() << "types" << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = " << GetBlockID()
           << Endline();
}

void NaClDisTypesParser::InstallUnknownTypeForNextId() {
  Type *UnknownType = GetUnknownType();
  Tokens() << NextTypeId() << Space() << "=" << Space()
           << TokenizeType(UnknownType) << Semicolon()
           << TokenizeAbbrevIndex() << Endline();
  InstallType(UnknownType);
}

void NaClDisTypesParser::ProcessRecord() {
  ObjDumpSetRecordBitAddress(Record.GetStartBit());
  const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
  switch (Record.GetCode()) {
  case naclbitc::TYPE_CODE_NUMENTRY: {
    // NUMENTRY: [numentries]
    uint64_t Size = 0;
    if (Values.size() == 1) {
      Size = Values[0];
    } else {
      Errors() << "Count record should have 1 argument. Found: "
               << Values.size() << "\n";
    }
    if (!IsFirstRecord) {
      Errors() << "Count record not first record of types block\n";
    }
    Tokens() << "count" << Space() << Size << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    ExpectedNumTypes = Size;
    break;
  }
  case naclbitc::TYPE_CODE_VOID: {
    // VOID
    if (!Values.empty())
      Errors() << "Void record shouldn't have arguments. Found: "
               << Values.size() << "\n";
    Type *VoidType = GetVoidType();
    Tokens() << NextTypeId() << Space() << "=" << Space()
             << TokenizeType(VoidType) << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    InstallType(VoidType);
    break;
  }
  case naclbitc::TYPE_CODE_FLOAT: {
    // FLOAT
    if (!Values.empty())
      Errors() << "Float record shoudn't have arguments. Found: "
               << Values.size() << "\n";
    Type *FloatType = GetFloatType();
    Tokens() << NextTypeId() << Space() << "=" << Space()
             << TokenizeType(FloatType) << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    InstallType(FloatType);
    break;
  }
  case naclbitc::TYPE_CODE_DOUBLE: {
    // DOUBLE
    if (!Values.empty())
      Errors() << "Double record shound't have arguments. Found: "
               << Values.size() << "\n";
    Type *DoubleType = GetDoubleType();
    Tokens() << NextTypeId() << Space() << "=" << Space()
             << TokenizeType(DoubleType) << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    InstallType(DoubleType);
    break;
  }
  case naclbitc::TYPE_CODE_INTEGER: {
    // INTEGER: [width]
    uint64_t Size;
    if (Values.size() == 1) {
      Size = Values[0];
    } else {
      Errors() << "Integer record should have one argument. Found: "
               << Values.size() << "\n";
      Size = 32;
    }
    switch (Size) {
      case 1:
      case 8:
      case 16:
      case 32:
      case 64: {
        break;
      }
      default:
        if (!IgnorePNaClABIChecks) {
          Errors() << "Integer record contains bad integer size: "
                   << Size << "\n";
          Size = 32;
        }
        break;
    }
    Type *IntType = GetIntegerType(Size);
    Tokens() << NextTypeId() << Space() << "=" << Space()
             << TokenizeType(IntType) << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    InstallType(IntType);
    break;
  }
  case naclbitc::TYPE_CODE_VECTOR: {
    // VECTOR: [numelts, eltty]
    if (Values.size() != 2) {
      Errors() << "Vector record should contain two arguments. Found: "
               << Values.size() << "\n";
      InstallUnknownTypeForNextId();
      break;
    }
    Type *BaseType = GetType(Values[1]);
    if (!(BaseType->isIntegerTy()
          || BaseType->isFloatTy()
          || BaseType->isDoubleTy())) {
      Type *ErrorRecoveryTy = GetIntegerType(32);
      Errors() << "Vectors can only be defined on primitive types. Found "
               << *BaseType << ". Assuming " << *ErrorRecoveryTy
               << " instead.\n";
      BaseType = ErrorRecoveryTy;
    }
    uint64_t NumElements = Values[0];
    Type *VecType = VectorType::get(BaseType, NumElements);
    if (!IgnorePNaClABIChecks &&
        !PNaClABITypeChecker::isValidVectorType(VecType)) {
      Errors() << "Vector type " << *VecType << " not allowed.\n";
    }
    Tokens() << NextTypeId() << Space() << "=" << Space()
             << TokenizeType(VecType) << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    InstallType(VecType);
    break;
  }
  case naclbitc::TYPE_CODE_FUNCTION: {
    // FUNCTION: [vararg, retty, paramty x N]
    if (Values.size() < 2) {
      Errors()
          << "Function record should contain at least 2 arguments. Found: "
          << Values.size() << "\n";
      InstallUnknownTypeForNextId();
      break;
    }
    if (Values[0]) {
      Errors() << "Functions with variable length arguments is not supported\n";
    }
    Type *ReturnType = GetType(Values[1]);
    if (!(isValidValueType(ReturnType) || ReturnType->isVoidTy())) {
      Type *ReplaceType = GetIntegerType(32);
      Errors() << "Invalid return type. Found: " << *ReturnType
               << ". Assuming: " << *ReplaceType << "\n";
      ReturnType = ReplaceType;
    }
    SmallVector<Type*, 8> Signature;
    for (size_t i = 2; i < Values.size(); ++i) {
      Type *Ty = GetType(Values[i]);
      if (!isValidValueType(Ty)) {
        Type *ReplaceTy = GetIntegerType(32);
        Errors() << "Invalid type for parameter " << (i - 1) << ". Found: "
                 << *Ty << ". Assuming: " << *ReplaceTy << "\n";
        Ty = ReplaceTy;
      }
      Signature.push_back(Ty);
    }
    Type *FcnType =  FunctionType::get(ReturnType, Signature, Values[0]);
    Tokens() << NextTypeId() << Space() << "=" << Space()
             << StartCluster() << TokenizeType(FcnType)
             << Semicolon() << FinishCluster() << TokenizeAbbrevIndex()
             << Endline();
    InstallType(FcnType);
    break;
  }
  default:
    Errors() << "Unknown record code in types block. Found: "
             << Record.GetCode() << "\n";
    break;
  }
  ObjDumpWrite(Record.GetStartBit(), Record);
  IsFirstRecord = false;
}

/// Parses and disassembles the globalvars block.
class NaClDisGlobalsParser : public NaClDisBlockParser {
public:
  NaClDisGlobalsParser(unsigned BlockID,
                       NaClDisBlockParser *EnclosingParser)
      : NaClDisBlockParser(BlockID, EnclosingParser),
        NumInitializers(0),
        InsideCompound(false),
        BaseTabs(GetAssemblyNumTabs()+1) {}

  ~NaClDisGlobalsParser() override {}

private:
  void PrintBlockHeader() override;

  void ProcessRecord() override;

  void ExitBlock() override;

  // Expected number of initializers associated with last globalvars
  // record
  uint32_t NumInitializers;
  // True if last globalvars record was defined by a compound record.
  bool InsideCompound;
  // Number of tabs used to indent elements in the globals block.
  unsigned BaseTabs;

  // Returns the ID for the next defined global.
  BitcodeId NextGlobalId() {
    return BitcodeId('g', GetNumGlobals());
  }

  // Prints out the close initializer "}" if necessary, and fixes
  // the indentation to match previous indentation.
  void InsertCloseInitializer();

  uint32_t GetExpectedNumGlobals() const {
    return Context->GetExpectedNumGlobals();
  }
};

void NaClDisGlobalsParser::PrintBlockHeader() {
  Tokens() << "globals" << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = " << GetBlockID()
           << Endline();
}

void NaClDisGlobalsParser::InsertCloseInitializer() {
  if (InsideCompound) {
    while (BaseTabs + 1 < GetAssemblyNumTabs()) DecAssemblyIndent();
    Tokens() << CloseCurly() << Endline();
  }
  while (BaseTabs < GetAssemblyNumTabs()) DecAssemblyIndent();
  ObjDumpFlush();
  NumInitializers = 0;
  InsideCompound = false;
}

void NaClDisGlobalsParser::ExitBlock() {
  if (NumInitializers > 0) {
    BitcodeId LastGlobal('g', (GetNumGlobals()-1));
    Errors() << "More initializers for " << LastGlobal << " expected: "
             << NumInitializers << "\n";
  }
  if (GetNumGlobals() != GetExpectedNumGlobals()) {
    Errors() << "Expected " << GetExpectedNumGlobals()
             << " globals but found: " << GetNumGlobals() << "\n";
  }
  NaClDisBlockParser::ExitBlock();
}

void NaClDisGlobalsParser::ProcessRecord() {
  ObjDumpSetRecordBitAddress(Record.GetStartBit());
  const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
  switch (Record.GetCode()) {
  case naclbitc::GLOBALVAR_VAR: {
    // VAR: [align, isconst]
    if (Values.size() != 2) {
      Errors() << "Globalvar record expects two arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    if (GetNumGlobals() == GetExpectedNumGlobals()) {
      Errors() << "Exceeded expected number of globals: "
               << GetExpectedNumGlobals() << "\n";
    }
    if (NumInitializers > 0) {
      Errors() << "Previous initializer list too short. Expects "
               << NumInitializers << " more initializers\n";
      InsertCloseInitializer();
    }
    uint32_t Alignment = (1 << Values[0]) >> 1;
    Tokens() << StartCluster() << (Values[1] ? "const" : "var")
             << Space() << NextGlobalId()
             << Comma() << FinishCluster() << Space()
             << StartCluster() << "align" << Space() << Alignment
             << Comma() << FinishCluster() << TokenizeAbbrevIndex()
             << Endline();
    IncAssemblyIndent();
    IncNumGlobals();
    NumInitializers = 1;
    break;
  }
  case naclbitc::GLOBALVAR_COMPOUND:
    // COMPOUND: [size]
    if (Values.size() != 1) {
      Errors() << "Compound record expects one argument. Found: "
               << Values.size() << "\n";
      break;
    }
    if (NumInitializers == 1) {
      if (InsideCompound) {
        Errors() << "Nested initialization records not allowed\n";
        InsertCloseInitializer();
      }
    } else {
      Errors() << "Compound record must follow globalvars record\n";
      InsertCloseInitializer();
    }
    Tokens() << StartCluster() << "initializers" << Space()
             << Values[0] << FinishCluster() << Space()
             << OpenCurly() << TokenizeAbbrevIndex() << Endline();
    IncAssemblyIndent();
    NumInitializers = Values[0];
    InsideCompound = true;
    break;
  case naclbitc::GLOBALVAR_ZEROFILL:
    // ZEROFILL: [size]
    if (Values.size() != 1) {
      Errors() << "Zerofill record expects one argument. Found: "
               << Values.size() << "\n";
      break;
    }
    if (NumInitializers == 0) {
      Errors() << "Zerofill initializer not associated with globalvar record\n";
    }
    Tokens() << "zerofill" << Space() << Values[0] << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    --NumInitializers;
    break;
  case naclbitc::GLOBALVAR_DATA: {
    // DATA: [b0, b1, ...]
    if (Values.empty()) {
      Errors() << "Globals data record must have arguments.\n";
    }
    if (NumInitializers == 0) {
      Errors() << "Data initializer not associated with globalvar record\n";
    }
    Tokens() << StartCluster() << OpenCurly();
    for (size_t i = 0; i < Values.size(); ++i) {
      if (i > 0) Tokens() << Comma() << FinishCluster() << Space();
      uint64_t Byte = Values[i];
      if (Byte >= 256) {
        Errors() << "Invalid byte value in data record: " << Byte << "\n";
        Byte &= 0xFF;
      }
      if (i > 0) Tokens() << StartCluster();
      Tokens() << format("%3u", static_cast<unsigned>(Byte));
    }
    Tokens() << CloseCurly() << FinishCluster() << TokenizeAbbrevIndex()
             << Endline();
    --NumInitializers;
    break;
  }
  case naclbitc::GLOBALVAR_RELOC:
    // RELOC: [val, [addend]]
    if (Values.empty() || Values.size() > 2) {
      Errors() << "Invalid reloc record size: " << Values.size() << "\n";
      break;
    }
    if (NumInitializers == 0) {
      Errors() <<
          "Relocation initializer not associated with globalvar record\n";
    }
    Tokens() << "reloc" << Space() << StartCluster() << GetBitcodeId(Values[0]);
    if (Values.size() == 2) {
      int32_t Addend = static_cast<int32_t>(Values[1]);
      char Operator = '+';
      if (Addend < 0) {
        Operator = '-';
        Addend = -Addend;
      }
      Tokens() << Space()<< Operator << Space() << Addend;
    }
    Tokens() << Semicolon() << FinishCluster() << TokenizeAbbrevIndex()
             << Endline();
    --NumInitializers;
    break;
  case naclbitc::GLOBALVAR_COUNT: {
    // COUNT: [n]
    uint32_t Count = 0;
    if (Values.size() == 1) {
      Count = Values[0];
    } else {
      Errors() << "Globals count record expects one argument. Found: "
               << Values.size() << "\n";
    }
    if (GetNumGlobals() != 0)
      Errors() << "Count record not first record in block.\n";
    Tokens() << "count" << Space() << Count << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    Context->SetExpectedNumGlobals(Count);
    break;
  }
  default:
    Errors() << "Unknown record found in globals block.\n";
  }

  ObjDumpWrite(Record.GetStartBit(), Record);

  if (GetNumGlobals() > 0 && NumInitializers == 0)
    InsertCloseInitializer();
}

/// Parsers and disassembles a valuesymtab block.
class NaClDisValueSymtabParser : public NaClDisBlockParser {
public:
  NaClDisValueSymtabParser(unsigned BlockID,
                           NaClDisBlockParser *EnclosingParser)
      : NaClDisBlockParser(BlockID, EnclosingParser) {
  }

  ~NaClDisValueSymtabParser() override {}

private:
  void PrintBlockHeader() override;

  void ProcessRecord() override;

  // Displays the context of the name (in Values) for the given Id.
  void DisplayEntry(BitcodeId &Id,
                    const NaClBitcodeRecord::RecordVector &Values);
};

void NaClDisValueSymtabParser::PrintBlockHeader() {
  Tokens() << "valuesymtab" << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = " << GetBlockID()
           << Endline();
}

void NaClDisValueSymtabParser::
DisplayEntry(BitcodeId &Id,
             const NaClBitcodeRecord::RecordVector &Values) {
  if (Values.size() <= 1) {
    Errors() << "Valuesymtab entry record expects 2 arguments. Found: "
             << Values.size() << "\n";
    return;
  }
  Tokens() << Id << Space() << Colon() << Space();
  // Check if the name of the symbol is alphanumeric. If so, print
  // as a string. Otherwise, print a sequence of bytes.
  // Note: The check isChar6 is a test for aphanumeric + {'.', '_'}.
  bool IsChar6 = true;  // Until proven otherwise.
  for (size_t i = 1; i < Values.size(); ++i) {
    uint64_t Byte = Values[i];
    if (Byte >= 256) {
      Errors() << "Argument " << i << " of symbol entry not byte: "
               << Byte << "\n";
      IsChar6 = false;
      break;
    }
    if (!NaClBitCodeAbbrevOp::isChar6(Byte))
      IsChar6 = false;
  }
  if (IsChar6) {
    Tokens() << StartCluster() << "\"";
    for (size_t i = 1; i < Values.size(); ++i) {
      Tokens() << static_cast<char>(Values[i]);
    }
    Tokens() << "\"" << Semicolon();
  } else {
    Tokens() << StartCluster() << OpenCurly();
    for (size_t i = 1; i < Values.size(); ++i) {
      if (i > 1) {
        Tokens() << Comma() << FinishCluster() << Space()
                 << StartCluster();
      }
      char ch = Values[i];
      if (NaClBitCodeAbbrevOp::isChar6(ch)) {
        Tokens() << "'" << ch << "'";
      } else {
        Tokens() << format("%3u", static_cast<unsigned>(ch));
      }
    }
    Tokens() << CloseCurly();
  }
  Tokens() << FinishCluster() << TokenizeAbbrevIndex() << Endline();
}

void NaClDisValueSymtabParser::ProcessRecord() {
  ObjDumpSetRecordBitAddress(Record.GetStartBit());
  const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
  switch (Record.GetCode()) {
  case naclbitc::VST_CODE_ENTRY: {
    // VST_ENTRY: [valueid, namechar x N]
    uint32_t ValID = Values[0];
    BitcodeId ID(GetBitcodeId(ValID));
    DisplayEntry(ID, Values);
    if (ValID < GetNumFunctions()) {
      // Check if value is intrinsic name. If so, verify function signature.
      std::string Name;
      for (unsigned i = 1; i < Values.size(); ++i) {
        Name.push_back(static_cast<char>(Values[i]));
      }
      FunctionType *IntrinTy = Context->GetIntrinsicType(Name);
      if (IntrinTy == 0)
        // TODO(kschimpf): Check for _start? Complain about other names?
        break;
      Context->MarkFunctionAsIntrinsic(ValID);
      // Verify that expected intrinsic function type matches declared
      // type signature.
      FunctionType *FcnTy = GetFunctionType(ValID);
      if (FcnTy->getNumParams() != IntrinTy->getNumParams()) {
        Errors() << "Intrinsic " << Name
                 << " expects " << IntrinTy->getNumParams()
                 << " arguments. Found: " << FcnTy->getNumParams()
                 << "\n";
        break;
      }
      if (!IgnorePNaClABIChecks && !PNaClABITypeChecker::IsPointerEquivType(
              IntrinTy->getReturnType(), FcnTy->getReturnType())) {
        Errors() << "Intrinsic " << Name
                 << " expects return type " << *IntrinTy->getReturnType()
                 << ". Found: " << *FcnTy->getReturnType() << "\n";
        break;
      }
      for (size_t i = 0; i < FcnTy->getNumParams(); ++i) {
        if (!IgnorePNaClABIChecks && !PNaClABITypeChecker::IsPointerEquivType(
                IntrinTy->getParamType(i),
                FcnTy->getParamType(i))) {
          Errors() << "Intrinsic " << Name
                   << " expects " << *IntrinTy->getParamType(i)
                   << " for argument " << (i+1) << ". Found: "
                   << *FcnTy->getParamType(i) << "\n";
          break;
        }
      }
    }
    break;
  }
  case naclbitc::VST_CODE_BBENTRY: {
    // [bbid, namechar x N]
    BitcodeId ID('b', Values[0]);
    DisplayEntry(ID, Values);
    break;
  }
  default:
    Errors() << "Unknown record in valuesymtab block.\n";
    break;
  }
  ObjDumpWrite(Record.GetStartBit(), Record);
}

/// Parses and disassembles a constants block.
class NaClDisConstantsParser : public NaClDisBlockParser {
public:
  NaClDisConstantsParser(unsigned BlockID,
                         NaClDisBlockParser *EnclosingParser)
      : NaClDisBlockParser(BlockID, EnclosingParser),
        ConstantType(0),
        BlockTabs(GetAssemblyNumTabs()) {}

  virtual ~NaClDisConstantsParser() {
    while (BlockTabs < GetAssemblyNumTabs()) DecAssemblyIndent();
  }

private:
  void PrintBlockHeader() override;

  void ProcessRecord() override;

  /// Generates the value id for the next generated constant.
  BitcodeId NextConstId() {
    return BitcodeId('c', GetNumConstants());
  }

  // The type associated with the constant.
  Type *ConstantType;
  // The number of tabs used to indent the globals block.
  unsigned BlockTabs;
};

void NaClDisConstantsParser::PrintBlockHeader() {
  Tokens() << "constants" << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = " << GetBlockID()
           << Endline();
}

void NaClDisConstantsParser::ProcessRecord() {
  ObjDumpSetRecordBitAddress(Record.GetStartBit());
  const NaClBitcodeRecord::RecordVector Values = Record.GetValues();
  switch (Record.GetCode()) {
  case naclbitc::CST_CODE_SETTYPE:
    // SETTYPE: [typeid]
    while (BlockTabs + 1 < GetAssemblyNumTabs()) DecAssemblyIndent();
    if (Values.size() == 1) {
      ConstantType = GetType(Values[0]);
      Tokens() << TokenizeType(ConstantType) << ":"
               << TokenizeAbbrevIndex() << Endline();
    } else {
      Errors() << "Settype record should have 1 argument. Found: "
               << Values.size() << "\n";
      // Make up a type, so we can continue.
      ConstantType = GetIntegerType(32);
    }
    IncAssemblyIndent();
    break;
  case naclbitc::CST_CODE_UNDEF:
    // CST_CODE_UNDEF: []
    if (!Values.empty()) {
      Errors() << "Undefined record should not have arguments: Found: "
               << Values.size() << "\n";
    }
    Tokens() << NextConstId() << Space() << "=" << Space()
             << StartCluster() << TokenizeType(ConstantType)
             << Space() << "undef"
             << Semicolon() << FinishCluster()
             << TokenizeAbbrevIndex() << Endline();
    InstallConstantType(ConstantType);
    break;
  case naclbitc::CST_CODE_INTEGER: {
    // INTEGER: [intval]
    SignRotatedInt Value;
    if (Values.size() == 1) {
      const SignRotatedInt MyValue(Values[0], ConstantType);
      Value = MyValue;
    } else {
      Errors() << "Integer record should have 1 argument. Found: "
               << Values.size() << "\n";
    }
    Tokens() << NextConstId() << Space() << "=" << Space() << StartCluster()
             << StartCluster() << TokenizeType(ConstantType) << Space()
             << Value << Semicolon() << FinishCluster() << FinishCluster()
             << TokenizeAbbrevIndex() << Endline();
    InstallConstantType(ConstantType);
    break;
  }
  case naclbitc::CST_CODE_FLOAT: {
    // FLOAT: [fpval]
    // Define initially with default value zero, in case of errors.
    const fltSemantics &FloatRep =
        ConstantType->isFloatTy() ? APFloat::IEEEsingle : APFloat::IEEEdouble;
    APFloat Value(APFloat::getZero(FloatRep));
    if (Values.size() == 1) {
      if (ConstantType->isFloatTy()) {
        Value = APFloat(FloatRep, APInt(32, static_cast<uint32_t>(Values[0])));
      }
      else if (ConstantType->isDoubleTy()) {
        Value = APFloat(FloatRep, APInt(64, Values[0]));
      } else {
        Errors() << "Bad floating point constant argument: "
                 << Values[0] << "\n";
      }
    } else {
      Errors() << "Float record should have 1 argument. Found: "
               << Values.size() << "\n";
    }
    Tokens() << NextConstId() << Space() << "=" << Space() << StartCluster()
             << TokenizeType(ConstantType) << Space();
    if (ConstantType->isFloatTy()) {
      Tokens() << format("%g", Value.convertToFloat());
    } else {
      Tokens() << format("%g", Value.convertToDouble());
    }
    Tokens() << Semicolon() << FinishCluster()
             << TokenizeAbbrevIndex() << Endline();
    InstallConstantType(ConstantType);
    break;
  }
  default:
    Errors() << "Unknown record in valuesymtab block.\n";
    break;
  }
  ObjDumpWrite(Record.GetStartBit(), Record);
}

/// Parses and disassembles function blocks.
class NaClDisFunctionParser : public NaClDisBlockParser {
public:
  NaClDisFunctionParser(unsigned BlockID,
                        NaClDisBlockParser *EnclosingParser);

  ~NaClDisFunctionParser() override {}

  void PrintBlockHeader() override;

  bool ParseBlock(unsigned BlockID) override;

  void ProcessRecord() override;

  /// Returns the absolute value index of the first instruction that
  /// generates a value in the defined function.
  uint32_t FirstValuedInstructionId() const {
    return GetNumFunctions() + GetNumGlobals() + GetNumParams()
        + GetNumConstants();
  }

  /// Converts an instruction index to the corresponding absolute value
  /// index.
  uint32_t ValuedInstToAbsId(uint32_t Id) const {
    return FirstValuedInstructionId() + Id;
  }

  /// Converts the (function) relative index to the corresponding
  /// absolute value index.
  uint32_t RelativeToAbsId(int32_t Id) {
    uint32_t AbsNextId = ValuedInstToAbsId(GetNumValuedInstructions());
    if (Id > 0 && AbsNextId < static_cast<uint32_t>(Id)) {
      Errors() << "Invalid relative value id: " << Id
               << " (Must be <= " << AbsNextId << ")\n";
      AbsNextId = Id;
    }
    return AbsNextId - Id;
  }

  /// Converts the given absolute value index to a corresponding
  /// valued instruction index.
  uint32_t AbsToValuedInstId(uint32_t Id) const {
    return Id - FirstValuedInstructionId();
  }

  /// Returns the text representation of the encoded binary operator,
  /// assuming the binary operator is operating on the given type.
  /// Generates appropriate error messages if the given type is not
  // allowed for the given Opcode.
  const char *GetBinop(uint32_t Opcode, Type *Type);

  /// Returns the text representation of the encoded cast operator.
  /// Generates appropriate error messages if the given Opcode is
  /// not allowed for the given types.
  const char *GetCastOp(uint32_t Opcode, Type *FromType, Type *ToType);

  /// Returns the text representation of the encoded integer compare
  /// predicate. Generates appropriate error message if the given
  /// Opcode is not defined.
  const char *GetIcmpPredicate(uint32_t Opcode);

  /// Returns the text representation of the encoded floating point
  /// compare predicate. Generates appropriate error message if the
  /// given Opcode is not defined.
  const char *GetFcmpPredicate(uint32_t Opcode);

  /// Returns the value id for the next instruction to be defined.
  BitcodeId NextInstId() const {
    return BitcodeId('v', GetNumValuedInstructions());
  }

private:
  // The function index of the function being defined.
  uint32_t FcnId;
  // The function type for the function being defined.
  FunctionType *FcnTy;
  // The current basic block being printed.
  int32_t CurrentBbIndex;
  // The expected number of basic blocks.
  uint64_t ExpectedNumBbs;
  // True if the previously printed instruction was a terminating
  // instruction. Used to figure out where to insert block labels.
  bool InstIsTerminating;

  /// Returns scalar type of vector type Ty, if vector type. Otherwise
  /// returns Ty.
  Type *UnderlyingType(Type *Ty) {
    return Ty->isVectorTy() ? Ty->getVectorElementType() : Ty;
  }

  bool isFloatingType(Type *Ty) {
    return Ty->isFloatTy() || Ty->isDoubleTy();
  }

  /// Verifies that OpTy is an integer, or a vector of integers, for
  /// operator Op. Generates error messages if appropriate. Returns Op.
  const char *VerifyIntegerOrVectorOp(const char *Op, Type *OpTy) {
    Type *BaseTy = OpTy;
    if (OpTy->isVectorTy()) {
      if (!IgnorePNaClABIChecks &&
          !PNaClABITypeChecker::isValidVectorType(OpTy)) {
        Errors() << Op << ": invalid vector type: " << *OpTy << "\n";
        return Op;
      }
      BaseTy = OpTy->getVectorElementType();
    }
    if (BaseTy->isIntegerTy()) {
      if (IgnorePNaClABIChecks ||
          PNaClABITypeChecker::isValidScalarType(BaseTy)) {
        return Op;
      }
      Errors() << Op << ": Invalid integer type: " << *OpTy << "\n";
    } else {
      Errors() << Op << ": Expects integer type. Found: " << *OpTy << "\n";
    }
    return Op;
  }

  /// Verifies that Opty is a floating point type, or a vector of a
  /// floating points, for operator Op. Generates error messages if
  /// appropriate. Returns Op.
  const char *VerifyFloatingOrVectorOp(const char *Op, Type *OpTy) {
    Type *BaseTy = OpTy;
    if (OpTy->isVectorTy()) {
      if (!IgnorePNaClABIChecks &&
          !PNaClABITypeChecker::isValidVectorType(OpTy)) {
        Errors() << Op << ": invalid vector type: " << *OpTy << "\n";
        return Op;
      }
      BaseTy = OpTy->getVectorElementType();
    }
    if (!isFloatingType(BaseTy)) {
      Errors() << Op << ": Expects floating point. Found "
               << OpTy << "\n";
      return Op;
    }
    if (!IgnorePNaClABIChecks &&
        !PNaClABITypeChecker::isValidScalarType(BaseTy)) {
      Errors() << Op << ": type not allowed: " << OpTy << "\n";
    }
    return Op;
  }

  /// Op is the name of the operation that called this.  Checks if
  /// OpTy is either a (non-void) scalar, or a vector of scalars. If
  /// not, generates an appropriate error message. Always returns Op.
  const char *VerifyScalarOrVectorOp(const char *Op, Type *OpTy) {
    if (IgnorePNaClABIChecks) return Op;
    if (PNaClABITypeChecker::isValidScalarType(OpTy)) {
      if (OpTy->isVoidTy())
        Errors() << Op << ": Type void not allowed\n";
    } else if (!PNaClABITypeChecker::isValidVectorType(OpTy)) {
      Errors() << Op << ": Expects scalar/vector type. Found: "
               << OpTy << "\n";
    }
    return Op;
  }

  void VerifyIndexedVector(const char *Op, uint32_t VecValue,
                           uint32_t IdxValue) {
    Type *VecType = GetValueType(VecValue);
    Type *IdxType = GetValueType(IdxValue);
    if (!IgnorePNaClABIChecks &&
        !PNaClABITypeChecker::isValidVectorType(VecType)){
      if (VecType->isVectorTy())
        Errors() << Op << ": Vector type " << *VecType << " not allowed\n";
      else
        Errors() << Op << ": Vector type expected. Found: " << *VecType << "\n";
    }
    // Note: This restriction appears to be LLVM specific.
    if (!IdxType->isIntegerTy(32)) {
      Errors() << Op << ": Index not i32. Found: " << *IdxType << "\n";
    }
    BitcodeId IdxId(GetBitcodeId(IdxValue));
    if (IdxId.GetKind() != 'c') {
      Errors() << Op << ": Vector index not constant: " << IdxId << "\n";
      // TODO(kschimpf): We should check that Idx is a constant with
      // valid access. However, we currently don't store constant
      // values, so it can't be tested.
    }
  }

  /// Checks if block Value is a valid branch target for the current
  /// function block. If not, generates an appropriate error message.
  void VerifyBranchRange(uint64_t Value) {
    if (0 == Value || Value >= ExpectedNumBbs) {
      Errors() << "Branch " << BitcodeId('b', Value)
               << " out of range. Not in [1," << ExpectedNumBbs << "]\n";
    }
  }

  /// Convert alignment exponent (i.e. power of two (or zero)) to the
  /// corresponding alignment to use. If alignment is too large, it generates
  /// an error message and returns 0.
  unsigned getAlignmentValue(uint64_t Exponent);
};

NaClDisFunctionParser::NaClDisFunctionParser(
    unsigned BlockID,
    NaClDisBlockParser *EnclosingParser)
    : NaClDisBlockParser(BlockID, EnclosingParser),
      CurrentBbIndex(-1),
      ExpectedNumBbs(0),
      InstIsTerminating(false) {
  Context->ResetLocalCounters();
  if (Context->HasNextDefinedFunctionIndex()) {
    FcnId = Context->GetNextDefinedFunctionIndex();
    FcnTy = GetFunctionType(FcnId);
  } else {
    FcnId = 0;
    SmallVector<Type*, 8> Signature;
    FcnTy = FunctionType::get(GetVoidType(), Signature, 0);
    Errors() <<
        "No corresponding defining function address for function block.\n";
    return;
  }
  Context->IncNumDefinedFunctions();

  // Now install parameters.
  for (size_t Index = 0; Index < FcnTy->getFunctionNumParams(); ++Index) {
    InstallParamType(FcnTy->getFunctionParamType(Index));
  }
}

void NaClDisFunctionParser::PrintBlockHeader() {
  Tokens() << "function" << Space();
  BitcodeId FunctionId('f', FcnId);
  bool InvalidSignature = true; // until proven otherwise.
  if (Context->IsFunctionIntrinsic(FcnId))
    InvalidSignature = false;
  else if (IgnorePNaClABIChecks ||
           PNaClABITypeChecker::isValidFunctionType(FcnTy)) {
      InvalidSignature = false;
  }
  if (InvalidSignature) {
    Errors() << "Invalid type signature for "
             << BitcodeId('f', FcnId) << ": " << *FcnTy << "\n";
  }
  Tokens() << TokenizeFunctionSignature(FcnTy, &FunctionId)
           << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = " << GetBlockID()
           << Endline();
}

const char *NaClDisFunctionParser::GetBinop(uint32_t Opcode, Type *Ty) {
  Instruction::BinaryOps LLVMOpcode;
  if (!naclbitc::DecodeBinaryOpcode(Opcode, Ty, LLVMOpcode)) {
    Errors() << "Binary opcode not understood: " << Opcode << "\n";
    return "???";
  }
  switch (LLVMOpcode) {
  default:
    Errors() << "Binary opcode not understood: " << Opcode << "\n";
    return "???";
  case Instruction::Add:
    return VerifyIntArithmeticOp("add", Ty);
  case Instruction::FAdd:
    return VerifyFloatingOrVectorOp("fadd", Ty);
  case Instruction::Sub:
    return VerifyIntArithmeticOp("sub", Ty);
  case Instruction::FSub:
    return VerifyFloatingOrVectorOp("fsub", Ty);
  case Instruction::Mul:
    return VerifyIntArithmeticOp("mul", Ty);
  case Instruction::FMul:
    return VerifyFloatingOrVectorOp("fmul", Ty);
  case Instruction::UDiv:
    return VerifyIntArithmeticOp("udiv", Ty);
  case Instruction::SDiv:
    return VerifyIntArithmeticOp("sdiv", Ty);
  case Instruction::FDiv:
    return VerifyFloatingOrVectorOp("fdiv", Ty);
  case Instruction::URem:
    return VerifyIntArithmeticOp("urem", Ty);
  case Instruction::SRem:
    return VerifyIntArithmeticOp("srem", Ty);
  case Instruction::FRem:
    return VerifyFloatingOrVectorOp("frem", Ty);
  case Instruction::Shl:
    return VerifyIntArithmeticOp("shl", Ty);
  case Instruction::LShr:
    return VerifyIntArithmeticOp("lshr", Ty);
  case Instruction::AShr:
    return VerifyIntArithmeticOp("ashr", Ty);
  case Instruction::And:
    return VerifyIntegerOrVectorOp("and", Ty);
  case Instruction::Or:
    return VerifyIntegerOrVectorOp("or", Ty);
  case Instruction::Xor:
    return VerifyIntegerOrVectorOp("xor", Ty);
  }
}

const char *NaClDisFunctionParser::GetCastOp(uint32_t Opcode,
                                             Type *FromType, Type *ToType) {
  Instruction::CastOps Cast;
  const char *CastName = "???";
  if (!naclbitc::DecodeCastOpcode(Opcode, Cast)) {
    Errors() << "Cast opcode not understood: " << Opcode << "\n";
    return CastName;
  }
  switch (Cast) {
  default:
    Errors() << "Cast opcode not understood: " << Opcode << "\n";
    return CastName;
  case Instruction::BitCast:
    CastName = "bitcast";
    break;
  case Instruction::Trunc:
    CastName = "trunc";
    break;
  case Instruction::ZExt:
    CastName = "zext";
    break;
  case Instruction::SExt:
    CastName = "sext";
    break;
  case Instruction::FPToUI:
    CastName = "fptoui";
    break;
  case Instruction::FPToSI:
    CastName = "fptosi";
    break;
  case Instruction::UIToFP:
    CastName = "uitofp";
    break;
  case Instruction::SIToFP:
    CastName = "sitofp";
    break;
  case Instruction::FPTrunc:
    CastName = "fptrunc";
    break;
  case Instruction::FPExt:
    CastName = "fpext";
    break;
  }
  if (!CastInst::castIsValid(Cast, FromType, ToType)) {
    Errors() << "Invalid cast '" << CastName << "'. Not defined on "
             << FromType << " to " << ToType << "\n";
  }
  return CastName;
}

const char *NaClDisFunctionParser::GetIcmpPredicate(uint32_t Opcode) {
  CmpInst::Predicate Predicate;
  if (!naclbitc::DecodeIcmpPredicate(Opcode, Predicate)) {
    Errors() << "Icmp predicate not understood: " << Opcode << "\n";
    return "???";
  }
  switch (Predicate) {
  default:
    Errors() << "Icmp predicate not understood: " << Opcode << "\n";
    return "???";
  case CmpInst::ICMP_EQ:
    return "eq";
  case CmpInst::ICMP_NE:
    return "ne";
 case CmpInst::ICMP_UGT:
    return "ugt";
  case CmpInst::ICMP_UGE:
    return "uge";
  case CmpInst::ICMP_ULT:
    return "ult";
  case CmpInst::ICMP_ULE:
    return "ule";
  case CmpInst::ICMP_SGT:
    return "sgt";
  case CmpInst::ICMP_SGE:
    return "sge";
  case CmpInst::ICMP_SLT:
    return "slt";
  case CmpInst::ICMP_SLE:
    return "sle";
  }
}

const char *NaClDisFunctionParser::GetFcmpPredicate(uint32_t Opcode) {
  CmpInst::Predicate Predicate;
  if (!naclbitc::DecodeFcmpPredicate(Opcode, Predicate)) {
    Errors() << "Fcmp predicate not understood: " << Opcode << "\n";
    return "???";
  }
  switch (Predicate) {
  default:
    Errors() << "Fcmp predicate not understood: " << Opcode << "\n";
    return "???";
  case CmpInst::FCMP_FALSE:
    return "false";
  case CmpInst::FCMP_OEQ:
    return "oeq";
  case CmpInst::FCMP_OGT:
    return "ogt";
  case CmpInst::FCMP_OGE:
    return "oge";
  case CmpInst::FCMP_OLT:
    return "olt";
  case CmpInst::FCMP_OLE:
    return "ole";
  case CmpInst::FCMP_ONE:
    return "one";
  case CmpInst::FCMP_ORD:
    return "ord";
  case CmpInst::FCMP_UNO:
    return "uno";
  case CmpInst::FCMP_UEQ:
    return "ueq";
  case CmpInst::FCMP_UGT:
    return "ugt";
  case CmpInst::FCMP_UGE:
    return "uge";
  case CmpInst::FCMP_ULT:
    return "ult";
  case CmpInst::FCMP_ULE:
    return "ule";
  case CmpInst::FCMP_UNE:
    return "une";
  case CmpInst::FCMP_TRUE:
    return "true";
  }
}

namespace {

static const unsigned MaxAlignmentExponent = 29;
static_assert(
    (1u << MaxAlignmentExponent) == Value::MaximumAlignment,
    "Inconsistency between Value.MaxAlignment and PNaCl alignment limit");
}

unsigned NaClDisFunctionParser::getAlignmentValue(uint64_t Exponent) {
  if (Exponent > MaxAlignmentExponent + 1) {
    Errors() << "Alignment can't be greater than 2**" << MaxAlignmentExponent
             << ". Found: 2**" << (Exponent - 1) << "\n";
    return 0;
  }
  return (1 << static_cast<unsigned>(Exponent)) >> 1;
}

bool NaClDisFunctionParser::ParseBlock(unsigned BlockID) {
  ObjDumpSetRecordBitAddress(GetBlock().GetStartBit());
  switch (BlockID) {
  case naclbitc::CONSTANTS_BLOCK_ID: {
    NaClDisConstantsParser Parser(BlockID, this);
    return Parser.ParseThisBlock();
  }
  case naclbitc::VALUE_SYMTAB_BLOCK_ID: {
    if (!PNaClAllowLocalSymbolTables) break;
    NaClDisValueSymtabParser Parser(BlockID, this);
    return Parser.ParseThisBlock();
  }
  default:
    break;
  }
  return NaClDisBlockParser::ParseBlock(BlockID);
}

void NaClDisFunctionParser::ProcessRecord() {
  ObjDumpSetRecordBitAddress(Record.GetStartBit());
  const NaClBitcodeRecord::RecordVector Values = Record.GetValues();
  // Start by adding block label if previous instruction is terminating.
  if (InstIsTerminating) {
    InstIsTerminating = false;
    ++CurrentBbIndex;
    DecAssemblyIndent();
    Tokens() << BitcodeId('b', CurrentBbIndex) << ":" << Endline();
    ObjDumpFlush();
    IncAssemblyIndent();
  }
  switch (Record.GetCode()) {
  case naclbitc::FUNC_CODE_DECLAREBLOCKS:
    // DECLAREBLOCKS: [n]
    InstIsTerminating = true;  // Force block label on first instruction.
    if (Values.size() != 1) {
      Errors() << "Function blocks record expects a size argument.\n";
      break;
    }
    ExpectedNumBbs = Values[0];
    if (ExpectedNumBbs == 0) {
      Errors() << "Functions must contain at least one block.\n";
    }
    Tokens() << "blocks" << Space() << ExpectedNumBbs << Semicolon();
    break;
  case naclbitc::FUNC_CODE_INST_BINOP: {
    // BINOP: [opval, opval, opcode]
    if (Values.size() != 3) {
      Errors() << "Binop record expects 3 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    uint32_t Op1 = RelativeToAbsId(Values[0]);
    uint32_t Op2 = RelativeToAbsId(Values[1]);
    Type *Type1 = GetValueType(Op1);
    Type *Type2 = GetValueType(Op2);
    if (Type1 != Type2) {
      Errors() << "Binop argument types differ: " << *Type1 << " and "
               << *Type2 << "\n";
    }
    const char *Binop = GetBinop(Values[2], Type1);
    Tokens() << NextInstId() << Space() << "=" << Space() << Binop << Space()
             << TokenizeType(Type1) << Space() << GetBitcodeId(Op1) << Comma()
             << Space() << GetBitcodeId(Op2) << Semicolon();
    InstallInstType(Type1);
    break;
  }
  case naclbitc::FUNC_CODE_INST_CAST: {
    // CAST: [opval, destty, castopc]
    if (Values.size() != 3) {
      Errors() << "Cast record expects 3 argments. Found: "
               << Values.size() << "\n";
      break;
    }
    uint32_t Op = RelativeToAbsId(Values[0]);
    Type *FromType = GetValueType(Op);
    Type *ToType = GetType(Values[1]);
    const char *CastOp = GetCastOp(Values[2], FromType, ToType);
    Tokens() << NextInstId() << Space() << "=" << Space() << CastOp << Space()
             << TokenizeType(FromType) << Space() << GetBitcodeId(Op)
             << Space() << "to" << Space() << TokenizeType(ToType)
             << Semicolon();
    InstallInstType(ToType);
    break;
  }
  case naclbitc::FUNC_CODE_INST_RET: {
    // RET: [opval?]
    InstIsTerminating = true;
    Tokens() << "ret" << Space();
    switch (Values.size()) {
    default:
      Errors() << "Function return record expects an optional return argument. "
               << "Found: " << Values.size() << " arguments\n";
      break;
    case 0:
      Tokens() << "void";
      break;
    case 1: {
      uint32_t Op = RelativeToAbsId(Values[0]);
      Tokens() << TokenizeType(GetValueType(Op)) << Space()<< GetBitcodeId(Op);
      break;
    }
    }
    Tokens() << Semicolon();
    break;
  }
  case naclbitc::FUNC_CODE_INST_BR: {
    // BR: [bb#, bb#, opval] or [bb#]
    InstIsTerminating = true;
    if (Values.size() != 1 && Values.size() != 3) {
      Errors() << "Function branch record expects 1 or 3 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    Tokens() << "br" << Space();
    if (Values.size() == 3) {
      uint32_t OpIndex = RelativeToAbsId(Values[2]);
      if (GetValueType(OpIndex) != GetComparisonType())
        Errors() << "Branch condition not i1\n";
      Tokens() << StartCluster() << "i1" << Space() << GetBitcodeId(OpIndex)
               << Comma() << FinishCluster() << Space();
    }
    VerifyBranchRange(Values[0]);
    Tokens() << StartCluster() << "label" << Space()
             << BitcodeId('b', Values[0]);
    if (Values.size() == 3) {
      VerifyBranchRange(Values[1]);
      Tokens() << Comma() << FinishCluster() << Space()
               << StartCluster() << "label" << Space()
               << BitcodeId('b', Values[1]);
    }
    Tokens() << Semicolon() << FinishCluster();
    break;
  }
  case naclbitc::FUNC_CODE_INST_SWITCH: {
    // SWITCH:  [opty, op, bb#, n, (1, 1, int, bb#)*]
    InstIsTerminating = true;
    if (Values.size() < 4) {
      Errors()
          << "Function switch record expects at least 4 arguments. Found: "
          << Values.size() << "\n";
      break;
    }
    Type *OpType = GetType(Values[0]);
    uint32_t CondId = RelativeToAbsId(Values[1]);
    Type *CondType = GetValueType(CondId);
    if (OpType != CondType)
      Errors() << "Specified select type " << *OpType << " but found: "
               << *CondType << "\n";
    if (!IgnorePNaClABIChecks &&
        !PNaClABITypeChecker::isValidSwitchConditionType(CondType)) {
      Errors() << PNaClABITypeChecker::ExpectedSwitchConditionType(CondType)
               << "\n";
    }
    uint32_t DefaultBb = Values[2];
    unsigned NumCases = Values[3];
    VerifyBranchRange(DefaultBb);
    Tokens() << "switch" << Space() << StartCluster() << StartCluster()
             << TokenizeType(OpType) << Space() <<  GetBitcodeId(CondId)
             << FinishCluster() << Space() << "{" << FinishCluster()
             << Endline();
    IncAssemblyIndent();
    Tokens() << StartCluster() << "default" << ":" << Space()
             << FinishCluster() << StartCluster() << "br" << Space() << "label"
             << Space() << BitcodeId('b', DefaultBb) << Semicolon()
             << FinishCluster() << Endline();
    unsigned CurIdx = 4;
    for (unsigned i = 0; i < NumCases; ++i) {
      unsigned NumItems = Values[CurIdx++];
      bool IsSingleNumber = Values[CurIdx++];
      if (NumItems != 1 || !IsSingleNumber) {
        Errors() << "Case ranges are not supported in PNaCl\n";
        break;
      }
      SignRotatedInt CaseValue(Values[CurIdx++], OpType);
      // TODO(kschimpf) Check if CaseValue possible based on OpType.
      uint64_t Label = Values[CurIdx++];
      VerifyBranchRange(Label);
      Tokens() << StartCluster() << TokenizeType(OpType) << Space()
               << CaseValue << ":" << Space() << FinishCluster()
               << StartCluster() << "br" << Space() << "label" << Space()
               << BitcodeId('b', Label) << Semicolon() << FinishCluster()
               << Endline();
    }
    DecAssemblyIndent();
    Tokens() << "}";
    break;
  }
  case naclbitc::FUNC_CODE_INST_UNREACHABLE:
    // UNREACHABLE
    InstIsTerminating = true;
    if (!Values.empty()) {
      Errors() << "Function unreachable record expects no arguments. Found: "
               << Values.size() << "\n";
    }
    Tokens() << "unreachable" << Semicolon();
    break;
  case naclbitc::FUNC_CODE_INST_PHI: {
    // PHI: [ty, (val0, bb0)*]
    if (Values.size() < 3) {
      Errors() << "Function phi record expects at least 3 arguments. Found: "
               << Values.size() << "\n";
      break;
    } else if (Values.size() % 2 == 0) {
      Errors()
          << "Function phi records should have an odd number of arguments. "
          << "Found: " << Values.size() << "\n";
    }
    Type* OpType = GetType(Values[0]);
    Tokens() << NextInstId() << Space() << "=" << StartCluster() << Space()
             << "phi" << Space() << TokenizeType(OpType);
    for (size_t i = 1; i < Values.size(); i += 2) {
      if (i > 1) Tokens() << Comma();
      uint32_t Index = RelativeToAbsId(NaClDecodeSignRotatedValue(Values[i]));
      Tokens() << FinishCluster() << Space() << StartCluster() << OpenSquare()
               << GetBitcodeId(Index) << Comma() << Space()
               << BitcodeId('b', Values[i+1]) << CloseSquare();
    }
    Tokens() << Semicolon() << FinishCluster();
    InstallInstType(OpType);
    break;
  };
  case naclbitc::FUNC_CODE_INST_ALLOCA: {
    // ALLOCA:     [size, align]
    if (Values.size() != 2) {
      Errors() << "Function alloca record expects 2 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    uint32_t SizeOp = RelativeToAbsId(Values[0]);
    Type* SizeType = GetValueType(SizeOp);
    BitcodeId SizeId(GetBitcodeId(SizeOp));
    unsigned Alignment = getAlignmentValue(Values[1]);
    if (!IgnorePNaClABIChecks && !PNaClABIProps::isAllocaSizeType(SizeType))
      Errors() << PNaClABIProps::ExpectedAllocaSizeType() << "\n";
    // TODO(kschimpf) Are there any constraints on alignment?
    Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster()
             << "alloca" << Space() << "i8" << Comma() << FinishCluster()
             << Space() << StartCluster() << TokenizeType(SizeType) << Space()
             << SizeId << Comma() << FinishCluster() << Space()
             << StartCluster() <<"align" << Space() << Alignment << Semicolon()
             << FinishCluster();
    InstallInstType(GetPointerType());
    break;
  }
  case naclbitc::FUNC_CODE_INST_LOAD: {
    // LOAD: [op, align, ty]
    if (Values.size() != 3) {
      Errors() << "Function load record expects 3 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    unsigned Alignment = getAlignmentValue(Values[1]);
    Type *LoadType = GetType(Values[2]);
    VerifyScalarOrVectorOp("load", LoadType);
    Context->VerifyMemoryAccessAlignment("load", LoadType, Alignment);
    Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster()
             << "load" << Space() << TokenizeType(LoadType) << "*" << Space()
             << GetBitcodeId(RelativeToAbsId(Values[0])) << Comma()
             << FinishCluster() << Space() << StartCluster()
             << "align" << Space() << Alignment << Semicolon()
             << FinishCluster();
    InstallInstType(LoadType);
    break;
  }
  case naclbitc::FUNC_CODE_INST_STORE: {
    // STORE: [ptr, val, align]
    if (Values.size() != 3) {
      Errors() << "Function store record expects 3 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    unsigned Alignment = getAlignmentValue(Values[2]);
    uint32_t Val = RelativeToAbsId(Values[1]);
    Type *ValType = GetValueType(Val);
    VerifyScalarOrVectorOp("store", ValType);
    Context->VerifyMemoryAccessAlignment("store", ValType, Alignment);
    Tokens() << StartCluster() << "store" << Space() << TokenizeType(ValType)
             << Space() << GetBitcodeId(Val) << Comma() << FinishCluster()
             << Space() << StartCluster() << TokenizeType(ValType) << "*"
             << Space() << GetBitcodeId(RelativeToAbsId(Values[0])) << Comma()
             << FinishCluster() << Space() << StartCluster() << "align"
             << Space() << Alignment << Semicolon() << FinishCluster();
    break;
  }
  case naclbitc::FUNC_CODE_INST_CMP2: {
    // CMP2: [opval, opval, pred]
    if (Values.size() != 3) {
      Errors() << "Function compare record expects 3 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    uint32_t Arg1 = RelativeToAbsId(Values[0]);
    uint32_t Arg2 = RelativeToAbsId(Values[1]);
    Type *Arg1Type = GetValueType(Arg1);
    Type *Arg2Type = GetValueType(Arg2);
    if (Arg1Type != Arg2Type) {
      Errors() << "Arguments not of same type: " << *Arg1Type << " and "
               << *Arg2Type << "\n";
    }
    const char *Pred = "???";
    Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster();
    Type* BaseType = UnderlyingType(Arg1Type);
    if (BaseType->isIntegerTy()) {
      Pred = GetIcmpPredicate(Values[2]);
      Tokens() << "icmp" << Space() << Pred;
    } else if (isFloatingType(BaseType)) {
      Pred = GetFcmpPredicate(Values[2]);
      Tokens() << "fcmp" << Space() << Pred;
    } else {
      Errors() << "Compare not on integer/float type. Found: "
               << *Arg1Type << "\n";
      Tokens() << "cmp" << Space() << "???" "(" << Values[2] << ")";
    }
    Tokens() << FinishCluster() << Space() << StartCluster()
             << TokenizeType(Arg1Type) << Space () << GetBitcodeId(Arg1)
             << Comma() << FinishCluster() << Space() << StartCluster()
             << GetBitcodeId(Arg2) << Semicolon() << FinishCluster();
    Type *ResultType = GetComparisonType();
    if (Arg1Type->isVectorTy()) {
      ResultType = VectorType::get(ResultType,
                                   Arg1Type->getVectorNumElements());
    }
    InstallInstType(ResultType);
    break;
  }
  case naclbitc::FUNC_CODE_INST_VSELECT: {
    // VSELECT:    [opval, opval, pred]
    if (Values.size() != 3) {
      Errors() << "Select record expects 3 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    uint32_t CondValue = RelativeToAbsId(Values[2]);
    uint32_t ThenValue = RelativeToAbsId(Values[0]);
    uint32_t ElseValue = RelativeToAbsId(Values[1]);
    Type *CondType = GetValueType(CondValue);
    Type *ThenType = GetValueType(ThenValue);
    Type *ElseType = GetValueType(ElseValue);
    if (ThenType != ElseType) {
      Errors() << "Selected arguments not of same type: "
               << *ThenType << " and " << *ElseType << "\n";
    }
    Type *BaseType = UnderlyingType(ThenType);
    if (!(BaseType->isIntegerTy() || isFloatingType(BaseType))) {
      Errors() << "Select arguments not integer/float. Found: " << *ThenType;
    }
    Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster()
             << "select" << Space() << TokenizeType(CondType) << Space()
             << GetBitcodeId(CondValue) << Comma() << FinishCluster() << Space()
             << StartCluster() << TokenizeType(ThenType) << Space()
             << GetBitcodeId(ThenValue) << Comma() << FinishCluster() << Space()
             << StartCluster() << TokenizeType(ElseType) << Space()
             << GetBitcodeId(ElseValue) << Semicolon()
             << FinishCluster();
    InstallInstType(ThenType);
    break;
  }
  case naclbitc::FUNC_CODE_INST_EXTRACTELT: {
    // EXTRACTELT: [opval, opval]
    if (Values.size() != 2) {
      Errors() << "Extract element record expects 2 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    uint32_t VecValue = RelativeToAbsId(Values[0]);
    uint32_t IdxValue = RelativeToAbsId(Values[1]);
    VerifyIndexedVector("extractelement", VecValue, IdxValue);
    Type *VecType = GetValueType(VecValue);
    Type *IdxType = GetValueType(IdxValue);
    Tokens() << NextInstId() << Space() << " = " << Space() << StartCluster()
             << "extractelement" << Space() << TokenizeType(VecType) << Space()
             << GetBitcodeId(VecValue) << Comma() << FinishCluster() << Space()
             << StartCluster() << TokenizeType(IdxType) << Space()
             << GetBitcodeId(IdxValue) << Semicolon() << FinishCluster();
    InstallInstType(UnderlyingType(VecType));
    break;
  }
  case naclbitc::FUNC_CODE_INST_INSERTELT: {
    // INSERTELT:  [opval, opval, opval]
    uint32_t VecValue = RelativeToAbsId(Values[0]);
    uint32_t EltValue = RelativeToAbsId(Values[1]);
    uint32_t IdxValue = RelativeToAbsId(Values[2]);
    VerifyIndexedVector("insertelement", VecValue, IdxValue);
    Type *VecType = GetValueType(VecValue);
    Type *EltType = GetValueType(EltValue);
    Type *IdxType = GetValueType(IdxValue);
    if (EltType != UnderlyingType(VecType)) {
      Errors() << "insertelement: Illegal element type " << *EltType
               << ". Expected: " << *UnderlyingType(VecType) << "\n";
    }
    Tokens() << NextInstId() << Space() << " = " << Space() << StartCluster()
             << "insertelement" << Space() << TokenizeType(VecType) << Space()
             << GetBitcodeId(VecValue) << Comma() << FinishCluster() << Space()
             << StartCluster() << TokenizeType(EltType) << Space()
             << GetBitcodeId(EltValue) << Comma() << FinishCluster() << Space()
             << StartCluster() << TokenizeType(IdxType) << Space()
             << GetBitcodeId(IdxValue) << Semicolon() << FinishCluster();
    InstallInstType(VecType);
    break;
  }
  case naclbitc::FUNC_CODE_INST_CALL:
  case naclbitc::FUNC_CODE_INST_CALL_INDIRECT: {
    // CALL: [cc, fnid, arg0, arg1...]
    // CALL_INDIRECT: [cc, fnid, returnty, args...]
    if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
      if (Values.size() < 2) {
        Errors() << "Call record expects at least 2 arguments. Found: "
                 << Values.size() << "\n";
        break;
      }
    } else if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL_INDIRECT) {
      if (Values.size() < 3) {
        Errors() << "Call indirect record expects at least 3 arguments. Found: "
                 << Values.size() << "\n";
        break;
      }
    }
    unsigned IsTailCall = (Values[0] & 0x1);
    CallingConv::ID CallingConv;
    uint32_t FcnId = RelativeToAbsId(Values[1]);
    if (!naclbitc::DecodeCallingConv(Values[0]>>1, CallingConv))
      Errors() << "Call unknown calling convention:" << (Values[0]>>1) << "\n";
    if (!IgnorePNaClABIChecks &&
        !PNaClABIProps::isValidCallingConv(CallingConv)) {
      Errors() << "Call uses disallowed calling convention: "
               << PNaClABIProps::CallingConvName(CallingConv) << "("
               << CallingConv << ")\n";
    }
    FunctionType *FcnType = 0;
    Type *ReturnType = 0;
    size_t ArgIndex = 2;
    // Flag defining if type checking should be done on argument/return
    // types.
    bool CheckArgRetTypes = true;
    if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
      Type *FcnTy = GetFunctionValueType(FcnId);
      if (FunctionType *FcnTyp = dyn_cast<FunctionType>(FcnTy)) {
        // TODO(kschimpf) Add back signature checking once we know how
        // to handle intrinsics (which can violate general signature
        // rules).
        CheckArgRetTypes = false;
        FcnType = FcnTyp;
        ReturnType = FcnType->getReturnType();
      } else {
        Errors() << "Invalid function signature: " << *FcnTy << "\n";
        ReturnType = GetVoidType();
      }
    } else {
      ReturnType = GetType(Values[2]);
      ArgIndex = 3;
    }
    if (!ReturnType->isVoidTy()) {
      Tokens() << NextInstId() << Space() << "=" << Space();
    }
    if (IsTailCall) {
      Tokens() << "tail" << Space();
    }
    if (CheckArgRetTypes &&
        !IgnorePNaClABIChecks &&
        !PNaClABITypeChecker::isValidParamType(ReturnType)) {
      Errors() << "Invalid return type: " << *ReturnType << "\n";
    }
    Tokens() << "call" << Space();
    if (CallingConv != CallingConv::C) {
      Tokens() << PNaClABIProps::CallingConvName(CallingConv) << Space();
    }
    Tokens() << TokenizeType(ReturnType) << Space()
             << StartCluster() << GetBitcodeId(FcnId) << OpenParen()
             << StartCluster();
    unsigned ParamIndex = 0;
    unsigned NumParams = Values.size() + 1 - ArgIndex;
    for (size_t i = ArgIndex; i < Values.size(); ++i, ++ParamIndex) {
      uint32_t ParamId = RelativeToAbsId(Values[i]);
      Type *ParamType = GetValueType(ParamId);
      if (CheckArgRetTypes &&
          !IgnorePNaClABIChecks &&
          !PNaClABITypeChecker::isValidParamType(ParamType)) {
        Errors() << "invalid type for parameter " << i << ": "
                 << *ParamType << "\n";
      }
      if (FcnType) {
        if (ParamIndex < FcnType->getNumParams()) {
          Type *ExpectedType = FcnType->getParamType(ParamIndex);
          if (ParamType != ExpectedType) {
            Warnings() << "Parameter " << (ParamIndex + 1) << " mismatch: "
                       << *ParamType << " and " << *ExpectedType << "\n";
          }
        }
        else if (ParamIndex == FcnType->getNumParams()) {
          Warnings() << "Call expects " << FcnType->getNumParams()
                     << " arguments. Got: " << NumParams << "\n";
        }
      }
      if (i > ArgIndex) {
        Tokens() << Comma() << FinishCluster() << Space() << StartCluster();
      }
      Tokens() << TokenizeType(ParamType) << Space() << GetBitcodeId(ParamId);
    }
    Tokens() << CloseParen() << Semicolon() << FinishCluster()
             << FinishCluster();
    if (!ReturnType->isVoidTy()) InstallInstType(ReturnType);
    break;
  }
  case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF: {
    // TYPE: [opval, ty]
    if (Values.size() != 2) {
      Errors() << "Forward declare record expects 2 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    Type *OpType = GetType(Values[1]);
    Tokens() << "declare" << Space() << StartCluster()
             << TokenizeType(OpType) << Space()
             << GetBitcodeId(Values[0]) << Semicolon() << FinishCluster();
    InstallInstType(OpType, AbsToValuedInstId(Values[0]));
    break;
  }
  default:
    Errors() << "Unknown record found in module block.\n";
    break;
  }
  Tokens() << TokenizeAbbrevIndex() << Endline();
  ObjDumpWrite(Record.GetStartBit(), Record);
}

/// Parses and disassembles the module block.
class NaClDisModuleParser : public NaClDisBlockParser {
public:
  NaClDisModuleParser(unsigned BlockID, NaClDisTopLevelParser *Context)
      : NaClDisBlockParser(BlockID, Context) {
  }

  ~NaClDisModuleParser() override;

  bool ParseBlock(unsigned BlockID) override;

  void PrintBlockHeader() override;

  void ProcessRecord() override;
};

NaClDisModuleParser::~NaClDisModuleParser() {
  // Note: Since we can't check type signatures of most functions till
  // we know intrinsic names, and that isn't known until the (optional)
  // valuesymtab block is parsed, the only reasonable spot to check
  // function signatures is once the module block has been processed.
  unsigned NextFcnDefinedId = 0;
  for (unsigned i = 0, e = GetNumFunctions(); i < e; ++i) {
    // Note: If the type of a function isn't a function type, that
    // was checked in method ProcessRecord.
    // Note: If the function was defined, the type was checked in
    // NaClDisFunctionParser::PrintBlockHeader.
    if (Context->HasDefinedFunctionIndex(NextFcnDefinedId)
        && i == Context->GetDefinedFunctionIndex(NextFcnDefinedId)) {
      ++NextFcnDefinedId;
      continue;
    }
    if (FunctionType *FcnTy = dyn_cast<FunctionType>(GetFunctionValueType(i))) {
      if (!Context->IsFunctionIntrinsic(i) &&
          !IgnorePNaClABIChecks &&
          !PNaClABITypeChecker::isValidFunctionType(FcnTy)) {
        Context->SetRecordAddressToFunctionIdAddress(i);
        Errors() << "Invalid type signature for "
                 << BitcodeId('f', i) << ": " << *FcnTy << "\n";
      }
    }
  }
}

bool NaClDisModuleParser::ParseBlock(unsigned BlockID) {
  ObjDumpSetRecordBitAddress(GetBlock().GetStartBit());
  switch (BlockID) {
  case naclbitc::BLOCKINFO_BLOCK_ID: {
    NaClDisBlockInfoParser Parser(BlockID, this);
    return Parser.ParseThisBlock();
  }
  case naclbitc::TYPE_BLOCK_ID_NEW: {
    NaClDisTypesParser Parser(BlockID, this);
    return Parser.ParseThisBlock();
  }
  case naclbitc::GLOBALVAR_BLOCK_ID: {
    NaClDisGlobalsParser Parser(BlockID, this);
    return Parser.ParseThisBlock();
  }
  case naclbitc::VALUE_SYMTAB_BLOCK_ID: {
    NaClDisValueSymtabParser Parser(BlockID, this);
    return Parser.ParseThisBlock();
  }
  case naclbitc::FUNCTION_BLOCK_ID: {
    NaClDisFunctionParser Parser(BlockID, this);
    return Parser.ParseThisBlock();
  }
  default:
    return NaClDisBlockParser::ParseBlock(BlockID);
  }
}

void NaClDisModuleParser::PrintBlockHeader() {
  Tokens() << "module" << Space() << OpenCurly()
           << Space() << Space() << "// BlockID = " << GetBlockID()
           << Endline();
}

void NaClDisModuleParser::ProcessRecord() {
  ObjDumpSetRecordBitAddress(Record.GetStartBit());
  const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
  switch (Record.GetCode()) {
  case naclbitc::MODULE_CODE_VERSION:
    // [version#]
    if (Values.size() != 1) {
      Errors() << "Version record should have one argument. Found: "
               << Values.size() << "\n";
      break;
    }
    Tokens() << "version" << Space() << Values[0] << Semicolon()
             << TokenizeAbbrevIndex() << Endline();
    break;
  case naclbitc::MODULE_CODE_FUNCTION: {
    // [type, callingconv, isproto, linkage]
    if (Values.size() != 4) {
      Errors() << "Function record should have 4 arguments. Found: "
               << Values.size() << "\n";
      break;
    }
    bool IsProto = (Values[2] != 0);
    Tokens() << StartCluster() << (IsProto ? "declare" : "define");
    uint32_t FcnId = GetNumFunctions();
    BitcodeId FcnName('f', FcnId);
    std::string FcnStrName(FcnName.GetName());
    GlobalValue::LinkageTypes Linkage;
    if (!naclbitc::DecodeLinkage(Values[3], Linkage)) {
      Errors() << "Unknown linkage value: " << Values[3] << "\n";
    } else {
      if (!IgnorePNaClABIChecks &&
          !PNaClABIProps::isValidGlobalLinkage(Linkage)) {
        Errors() << "Disallowed linkage type: "
                 << PNaClABIProps::LinkageName(Linkage) << "\n";
      }
      Tokens() << Space() << PNaClABIProps::LinkageName(Linkage);
    }
    CallingConv::ID CallingConv;
    if (!naclbitc::DecodeCallingConv(Values[1], CallingConv)) {
      Errors() << "Unknown calling convention value: " << Values[1] << "\n";
    } else if (PNaClABIProps::isValidCallingConv(CallingConv)) {
      if (CallingConv != CallingConv::C) {
        Tokens() << Space() << PNaClABIProps::CallingConvName(CallingConv);
      }
    } else {
      Errors() << "Function " << FcnStrName
               << " has disallowed calling convention: "
               << PNaClABIProps::CallingConvName(CallingConv)
               << " (" << CallingConv << ")\n";
    }
    Tokens() << FinishCluster() << Space() << StartCluster();
    Type *FcnType = GetType(Values[0]);
    FunctionType *FunctionTy = dyn_cast<FunctionType>(FcnType);
    if (FunctionTy) {
      Tokens() << TokenizeFunctionType(FunctionTy, &FcnName);
    } else {
      BitcodeId FcnTypeId('t', Values[0]);
      Errors() << "Not function type: " << FcnTypeId << " = "
               << *FcnType << "\n";
      Tokens() << "???";
      SmallVector<Type*, 1> Signature;
      FunctionTy = FunctionType::get(GetVoidType(), Signature, 0);
    }
    Tokens() << Semicolon() << FinishCluster() << TokenizeAbbrevIndex()
             << Endline();
    InstallFunctionType(FunctionTy);
    if (!IsProto) InstallDefinedFunction(FcnId);
    break;
  }
  default:
    Errors() << "Unknown record found in module block\n";
    break;
  }
  ObjDumpWrite(Record.GetStartBit(), Record);
}

bool NaClDisTopLevelParser::ParseBlock(unsigned BlockID) {
  // Before parsing top-level module block. Describe header by
  // reconstructing the corresponding header record.
  NaClBitcodeRecordData HeaderRecord;
  size_t HeaderSize = Header.getHeaderSize();
  HeaderRecord.Code = naclbitc::BLK_CODE_HEADER;
  NaClBitstreamCursor &Cursor = Record.GetCursor();
  uint64_t CurPos = Cursor.GetCurrentBitNo();
  Cursor.JumpToBit(0);
  for (size_t i = 0; i < HeaderSize; ++i) {
    HeaderRecord.Values.push_back(Cursor.Read(CHAR_BIT));
  }
  Cursor.JumpToBit(CurPos);
  if (ObjDump.GetDumpRecords() && ObjDump.GetDumpAssembly()) {
    if (HeaderSize >= 4) {
      const NaClRecordVector &Values = HeaderRecord.Values;
      Tokens() << "Magic" << Space() << "Number" << Colon()
               << Space() << StartCluster() << StartCluster() << "'"
               << (char) Values[0] << (char) Values[1]
               << (char) Values[2] << (char) Values[3]
               << "'" << FinishCluster() << Space()
               << StartCluster() << OpenParen()
               << Values[0] << Comma() << Space()
               << Values[1] << Comma() << Space()
               << Values[2] << Comma() << Space()
               << Values[3] << CloseParen() << FinishCluster()
               << FinishCluster() << Endline();
    }
    // Show interpretation of header as assembly.
    for (size_t i = 0; i < Header.NumberFields(); ++i) {
      Tokens() << Header.GetField(i)->Contents() << Endline();
    }
  }
  ObjDump.Write(0, HeaderRecord);

  if (BlockID != naclbitc::MODULE_BLOCK_ID)
    return Error("Module block expected at top-level, but not found");

  // Now parse a module block.
  NaClDisModuleParser Parser(BlockID, this);
  return Parser.ParseThisBlock();
}

}

namespace llvm {

bool NaClObjDump(MemoryBufferRef MemBuf, raw_ostream &Output,
                 bool NoRecords, bool NoAssembly) {
  // Create objects needed to run parser.
  naclbitc::ObjDumpStream ObjDump(Output, !NoRecords, !NoAssembly);

  if (MemBuf.getBufferSize() % 4 != 0) {
    ObjDump.Error()
        << "Bitcode stream should be a multiple of 4 bytes in length.\n";
    return true;
  }

  const unsigned char *BufPtr = (const unsigned char *)MemBuf.getBufferStart();
  const unsigned char *EndBufPtr = BufPtr+MemBuf.getBufferSize();
  const unsigned char *HeaderPtr = BufPtr;

  // Read header and verify it is good.
  NaClBitcodeHeader Header;
  if (Header.Read(HeaderPtr, EndBufPtr) || !Header.IsSupported()) {
    ObjDump.Error() << "Invalid PNaCl bitcode header.\n";
    return true;
  }

  // Create a bitstream reader to read the bitcode file.
  NaClBitstreamReader InputStreamFile(BufPtr, EndBufPtr,
                                      Header.getHeaderSize());
  NaClBitstreamCursor InputStream(InputStreamFile);

  // Parse the the bitcode file.
  ::NaClDisTopLevelParser Parser(Header, InputStream, ObjDump);
  int NumBlocksRead = 0;
  bool ErrorsFound = false;
  while (!InputStream.AtEndOfStream()) {
    ++NumBlocksRead;
    if (Parser.Parse()) ErrorsFound = true;
  }

  if (NumBlocksRead != 1) {
    ObjDump.Error() << "Expected 1 top level block in bitcode: Found:"
                    << NumBlocksRead << "\n";
    ErrorsFound = true;
  }

  ObjDump.Flush();
  return ErrorsFound || Parser.GetNumErrors() > 0;
}

}
